diff options
| -rw-r--r-- | src/corelib/tools/qlist.h | 23 | ||||
| -rw-r--r-- | tests/auto/corelib/tools/qlist/tst_qlist.cpp | 33 |
2 files changed, 51 insertions, 5 deletions
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index a11f7913dc7..e69b9aebabb 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -301,21 +301,27 @@ public: explicit QList(qsizetype size) : d(size) { - if (size) + if (size) { + Q_CHECK_PTR(d.data()); d->appendInitialize(size); + } } QList(qsizetype size, parameter_type t) : d(size) { - if (size) + if (size) { + Q_CHECK_PTR(d.data()); d->copyAppend(size, t); + } } inline QList(std::initializer_list<T> args) : d(qsizetype(args.size())) { - if (args.size()) + if (args.size()) { + Q_CHECK_PTR(d.data()); d->copyAppend(args.begin(), args.end()); + } } QList<T> &operator=(std::initializer_list<T> args) @@ -332,6 +338,7 @@ public: const auto distance = std::distance(i1, i2); if (distance) { d = DataPointer(qsizetype(distance)); + Q_CHECK_PTR(d.data()); // appendIteratorRange can deal with contiguous iterators on its own, // this is an optimization for C++17 code. if constexpr (std::is_same_v<std::decay_t<InputIterator>, iterator> || @@ -352,8 +359,10 @@ public: QList(qsizetype size, Qt::Initialization) : d(size) { - if (size) + if (size) { + Q_CHECK_PTR(d.data()); d->appendUninitialized(size); + } } // compiler-generated special member functions are fine! @@ -823,7 +832,10 @@ void QList<T>::reserve(qsizetype asize) } } - DataPointer detached(qMax(asize, size())); + qsizetype newSize = qMax(asize, size()); + DataPointer detached(newSize); + if (newSize) + Q_CHECK_PTR(detached.data()); detached->copyAppend(d->begin(), d->end()); if (detached.d_ptr()) detached->setFlag(Data::CapacityReserved); @@ -839,6 +851,7 @@ inline void QList<T>::squeeze() // must allocate memory DataPointer detached(size()); if (size()) { + Q_CHECK_PTR(detached.data()); if (d.needsDetach()) detached->copyAppend(d.data(), d.data() + d.size); else diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp index b91665f55da..a93079b33de 100644 --- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp +++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp @@ -301,6 +301,7 @@ private slots: void constructors_emptyReserveZero() const; void constructors_emptyReserve() const; void constructors_reserveAndInitialize() const; + void constructorsThrowOnSillySize() const; void copyConstructorInt() const { copyConstructor<int>(); } void copyConstructorMovable() const { copyConstructor<Movable>(); } void copyConstructorNoexceptMovable() const { copyConstructor<NoexceptMovable>(); } @@ -704,6 +705,38 @@ void tst_QList::constructors_reserveAndInitialize() const QCOMPARE(meaningoflife.i, 'n'); } +void tst_QList::constructorsThrowOnSillySize() const +{ +#ifdef QT_NO_EXCEPTIONS + QSKIP("Compiled without exception support"); +#else + // Only testing primitives for this; it should be enough. + using T = int; + QList<T> dummy(4, 1); + + // This should cause QArrayData::allocate() to overflow and thus return + // nullptr. + constexpr size_t MaxMemory = std::numeric_limits<size_t>::max() / 4 * 3; + static_assert(MaxMemory > size_t(std::numeric_limits<ptrdiff_t>::max())); + static_assert(MaxMemory / sizeof(T) < size_t(std::numeric_limits<ptrdiff_t>::max() - 1)); + constexpr qsizetype NumElements = MaxMemory / sizeof(T); + + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l(NumElements)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l(NumElements, 0)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l(NumElements, Qt::Uninitialized)); + + // Since we're here, we might as well test resize() and reserve(). + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l; l.reserve(NumElements)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l; l.resize(NumElements)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l; l.resize(NumElements, 0)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l; l.resizeForOverwrite(NumElements)); + + // The reversed iterators will cause QList to pass a negative size to + // QArrayData::allocate(), which is also silly. + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l(dummy.constEnd(), dummy.constBegin())); +#endif +} + template<typename T> void tst_QList::copyConstructor() const { |
