Fix aliasing problem in QVector::removeAll()

Since removeAll() takes its argument by cref, if passing a reference
to an element of the container to removeAll(), the element may be
deleted (overwritten) by anyother value, leading to UB.

Add a test that actually happens to fail for me without the patch,
even though that might not be guaranteed (we may invoke UB).

Change-Id: If8c795113aeb515f4a9bdf1e072395b932295667
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Marc Mutz 2017-11-22 01:05:52 +01:00
parent a0871ad225
commit 67391f0a57
2 changed files with 11 additions and 2 deletions

View File

@ -164,9 +164,10 @@ public:
const const_iterator ce = this->cend(), cit = std::find(this->cbegin(), ce, t);
if (cit == ce)
return 0;
// next operation detaches, so ce, cit may become invalidated:
// next operation detaches, so ce, cit, t may become invalidated:
const T tCopy = t;
const int firstFoundIdx = std::distance(this->cbegin(), cit);
const iterator e = end(), it = std::remove(begin() + firstFoundIdx, e, t);
const iterator e = end(), it = std::remove(begin() + firstFoundIdx, e, tCopy);
const int result = std::distance(it, e);
erase(it, e);
return result;

View File

@ -245,6 +245,7 @@ private slots:
void qhashInt() const { qhash<int>(); }
void qhashMovable() const { qhash<Movable>(); }
void qhashCustom() const { qhash<Custom>(); }
void removeAllWithAlias() const;
void removeInt() const;
void removeMovable() const;
void removeCustom() const;
@ -1722,6 +1723,13 @@ void tst_QVector::prependCustom() const
QCOMPARE(instancesCount, Custom::counter.loadAcquire());
}
void tst_QVector::removeAllWithAlias() const
{
QVector<QString> strings;
strings << "One" << "Two" << "Three" << "One" /* must be distinct, but equal */;
QCOMPARE(strings.removeAll(strings.front()), 2); // will trigger asan/ubsan
}
template<typename T>
void tst_QVector::remove() const
{