summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2015-02-21 09:57:09 +0100
committerMarc Mutz <marc.mutz@kdab.com>2015-02-22 13:45:50 +0000
commit6716fe8cfdeb5f8cd63d6dde8252b25d86622404 (patch)
tree7b2aec6aaad0335b509718e32d2fb54a2a8e3390
parent9a950655feb709ea515edbbdb66fa5d900dc62ec (diff)
QVector: fix use of invalid iterators in removeAll()
The c2m() function which converts a const_iterator into an iterator is a broken concept for an implicitly shared container such as QVector, because the act of calling begin() as the starting point already detaches and invalidates the c2m argument. This could be fixed in c2m, but the bug wasn't even in c2m, but in removeAll(), which called end() before c2m, so the c2m argument was already invalidated when entering c2m. The solution is to store the positions as indices instead of iterators before calling the first detaching function. Task-number: QTBUG-44592 Change-Id: I66cf4f1277e71148a4d5b5bbfb6a3369ad02db68 Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
-rw-r--r--src/corelib/tools/qvector.h4
-rw-r--r--tests/auto/corelib/tools/qvector/tst_qvector.cpp7
2 files changed, 10 insertions, 1 deletions
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 07c66bc393..e263b99c02 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -153,7 +153,9 @@ public:
const const_iterator ce = this->cend(), cit = std::find(this->cbegin(), ce, t);
if (cit == ce)
return 0;
- const iterator e = end(), it = std::remove(c2m(cit), e, t);
+ // next operation detaches, so ce, cit may become invalidated:
+ const int firstFoundIdx = std::distance(this->cbegin(), cit);
+ const iterator e = end(), it = std::remove(begin() + firstFoundIdx, e, t);
const int result = std::distance(it, e);
erase(it, e);
return result;
diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp
index 9a79d48472..256fa5e507 100644
--- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp
+++ b/tests/auto/corelib/tools/qvector/tst_qvector.cpp
@@ -1500,11 +1500,18 @@ void tst_QVector::remove() const
QVERIFY(myvec.removeOne(val2));
QCOMPARE(myvec, QVector<T>() << val1 << val3 << val1 << val3 << val1 << val2 << val3);
+ QVector<T> myvecCopy = myvec;
+ QVERIFY(myvecCopy.isSharedWith(myvec));
// removeAll()
QCOMPARE(myvec.removeAll(val4), 0);
+ QVERIFY(myvecCopy.isSharedWith(myvec));
QCOMPARE(myvec.removeAll(val1), 3);
+ QVERIFY(!myvecCopy.isSharedWith(myvec));
QCOMPARE(myvec, QVector<T>() << val3 << val3 << val2 << val3);
+ myvecCopy = myvec;
+ QVERIFY(myvecCopy.isSharedWith(myvec));
QCOMPARE(myvec.removeAll(val2), 1);
+ QVERIFY(!myvecCopy.isSharedWith(myvec));
QCOMPARE(myvec, QVector<T>() << val3 << val3 << val3);
// remove rest