diff options
author | Marc Mutz <marc.mutz@qt.io> | 2021-12-09 22:22:04 +0100 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2021-12-10 18:40:54 +0000 |
commit | 97e56d4fa43794c12df999745bd46ee889ae1c51 (patch) | |
tree | a6d92e6f3b059930facab788410ecfe7ef33ceb1 | |
parent | 61d386e232aa9868f5c0d58ed88bd8a08c292f08 (diff) |
QVarLengthArray: fix UB (precondition violation) in range-erase()
When the range-erase() function is called with an empty, valid range,
it passed equal iterators to both the first and the last arguments of
std::move(f, l, d) (the algorithm, not the cast). This is UB, since it
violates the algorithm's precondition that d ∉ [f,l). For non-empty
ranges, f > d, thus d < f, hence d ∉ [f,l), so everything is ok
_there_.
Fix the empty range case by returning early.
Reviewers may question the precondition, expecting that std::move(f,
l, f) just be a no-op, but the algorithm, as specified, performs
self-move-assignments in that case, which need not be supported. In
fact, the Hinnant criterion, itself only applicable if one calls for
self-swap-safety, asks for self-move-assignment-safety only for
objects in the moved-from state. QVarLengthArray, itself, meets only
the Hinnant criterion; self-move-assignment of non-empty QVLAs invokes
UB.
So, the UB here is real.
Qt 5.15 uses std::copy() here, which has the same precondition as
std::move(), and the same fix applies there, too.
[ChangeLog][QtCore][QVarLengthArray] Fixed a bug where range-erase()
could invoke undefined behavior when called with an empty range.
Change-Id: I656aa09d025168d6d9ef088ad4c6954d216f0d54
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 0800947d7d2127eacaabf66ee1702d4980897041)
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
-rw-r--r-- | src/corelib/tools/qvarlengtharray.h | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index af8fed35d3..125012e54b 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -537,6 +537,10 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA int f = int(abegin - ptr); int l = int(aend - ptr); int n = l - f; + + if (n == 0) // avoid UB in std::copy() below + return data() + f; + if (QTypeInfo<T>::isComplex) { std::copy(ptr + l, ptr + s, QT_MAKE_CHECKED_ARRAY_ITERATOR(ptr + f, s - f)); T *i = ptr + s; |