summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qlist.h23
-rw-r--r--tests/auto/corelib/tools/qlist/tst_qlist.cpp33
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
{