Clear pending results in ResultStore

Pending results were never cleared by result store. This led to memory
leaks when the results never transitioned to "visible" results

Change-Id: I674302eb51542ad5f4d918da68d616428c73ae9f
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
bb10
Andrei Golubev 2020-10-08 15:40:41 +02:00
parent 27499d25fb
commit c22aabe9bc
2 changed files with 93 additions and 9 deletions

View File

@ -151,6 +151,20 @@ protected:
QMap<int, ResultItem> pendingResults;
int filteredResults;
template <typename T>
static void clear(QMap<int, ResultItem> &store)
{
QMap<int, ResultItem>::const_iterator mapIterator = store.constBegin();
while (mapIterator != store.constEnd()) {
if (mapIterator.value().isVector())
delete reinterpret_cast<const QList<T> *>(mapIterator.value().result);
else
delete reinterpret_cast<const T *>(mapIterator.value().result);
++mapIterator;
}
store.clear();
}
public:
template <typename T>
int addResult(int index, const T *result)
@ -197,16 +211,11 @@ public:
template <typename T>
void clear()
{
QMap<int, ResultItem>::const_iterator mapIterator = m_results.constBegin();
while (mapIterator != m_results.constEnd()) {
if (mapIterator.value().isVector())
delete reinterpret_cast<const QList<T> *>(mapIterator.value().result);
else
delete reinterpret_cast<const T *>(mapIterator.value().result);
++mapIterator;
}
ResultStoreBase::clear<T>(m_results);
resultCount = 0;
m_results.clear();
insertIndex = 0;
ResultStoreBase::clear<T>(pendingResults);
filteredResults = 0;
}
};

View File

@ -53,6 +53,8 @@ private slots:
void filterMode();
void addCanceledResult();
void count();
void pendingResultsDoNotLeak_data();
void pendingResultsDoNotLeak();
private:
int int0;
int int1;
@ -477,5 +479,78 @@ void tst_QtConcurrentResultStore::count()
}
}
// simplified version of CountedObject from tst_qarraydata.cpp
struct CountedObject
{
CountedObject() : id(liveCount++)
{ }
CountedObject(const CountedObject &other) : id(other.id)
{
++liveCount;
}
~CountedObject()
{
--liveCount;
}
CountedObject &operator=(const CountedObject &) = default;
struct LeakChecker
{
LeakChecker()
: previousLiveCount(liveCount)
{
}
~LeakChecker()
{
QCOMPARE(liveCount, previousLiveCount);
}
private:
const size_t previousLiveCount;
};
int id = 0;
static size_t liveCount;
};
size_t CountedObject::liveCount = 0;
struct ResultStoreCountedObject : ResultStoreBase
{
~ResultStoreCountedObject() { clear<CountedObject>(); }
};
void tst_QtConcurrentResultStore::pendingResultsDoNotLeak_data()
{
QTest::addColumn<bool>("filterMode");
QTest::addRow("filter-mode-off") << false;
QTest::addRow("filter-mode-on") << true;
}
void tst_QtConcurrentResultStore::pendingResultsDoNotLeak()
{
QFETCH(bool, filterMode);
CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker);
ResultStoreCountedObject store;
store.setFilterMode(filterMode);
// lvalue
auto lvalueObj = CountedObject();
store.addResult(42, &lvalueObj);
// rvalue
store.moveResult(43, CountedObject());
// array
auto lvalueListOfObj = QList<CountedObject>({CountedObject(), CountedObject()});
store.addResults(44, &lvalueListOfObj);
}
QTEST_MAIN(tst_QtConcurrentResultStore)
#include "tst_qresultstore.moc"