diff options
author | Andrei Golubev <andrei.golubev@qt.io> | 2021-01-22 09:26:09 +0100 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2021-01-26 08:01:27 +0000 |
commit | 37e26d2b3011acc86bbda1e1f46114d7c8441915 (patch) | |
tree | b70b9156c8d7a86baaca8c41d9978f755b5ab78f | |
parent | ecc2a28cab4652cf21cb8752e136cf90cbe6008b (diff) |
Extend alignment of QArrayData to std::max_align_t in allocation
Make stricter alignment requirements for the allocated header
This strict alignment allows reallocateUnaligned() to property account
for the padding occurring in cases when
alignof(QArrayData) < alignof(T) <= alignof(std::max_align_t), which
happens to be the case on e.g. 32-bit platforms with specific alignment
requirements.
This adds 4 bytes (the difference between alignof(std::max_align_t) and
sizeof(QArrayData)) of overhead for QString, QByteArray and certain QLists
on 32-bit systems.
Task-number: QTBUG-90359
Pick-to: 6.0
Change-Id: I8176a4cc79f100ee772b09425e88fe8ff3ae226a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r-- | src/corelib/tools/qarraydata.cpp | 23 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qlist/tst_qlist.cpp | 30 |
2 files changed, 45 insertions, 8 deletions
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index 8ca315024d..3297b51cfe 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -184,6 +184,15 @@ static QArrayData *allocateData(qsizetype allocSize) return header; } + +namespace { +// QArrayData with strictest alignment requirements supported by malloc() +struct alignas(std::max_align_t) AlignedQArrayData : QArrayData +{ +}; +} + + void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment, qsizetype capacity, QArrayData::AllocationOption option) noexcept { @@ -197,13 +206,13 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al return nullptr; } - qsizetype headerSize = sizeof(QArrayData); - const qsizetype headerAlignment = alignof(QArrayData); + qsizetype headerSize = sizeof(AlignedQArrayData); + const qsizetype headerAlignment = alignof(AlignedQArrayData); if (alignment > headerAlignment) { - // Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we - // can properly align the data array. This assumes malloc is able to - // provide appropriate alignment for the header -- as it should! + // Allocate extra (alignment - Q_ALIGNOF(AlignedQArrayData)) padding + // bytes so we can properly align the data array. This assumes malloc is + // able to provide appropriate alignment for the header -- as it should! headerSize += alignment - headerAlignment; } Q_ASSERT(headerSize > 0); @@ -233,7 +242,7 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer, { Q_ASSERT(!data || !data->isShared()); - const qsizetype headerSize = sizeof(QArrayData); + const qsizetype headerSize = sizeof(AlignedQArrayData); qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option); if (Q_UNLIKELY(allocSize < 0)) return qMakePair<QArrayData *, void *>(nullptr, nullptr); diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp index 3975bec678..64123c61a7 100644 --- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp +++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -347,6 +347,8 @@ private slots: void fromReadOnlyData() const; + void qtbug_90359() const; + private: template<typename T> void copyConstructor() const; template<typename T> void add() const; @@ -3181,5 +3183,31 @@ void tst_QList::fromReadOnlyData() const } } +struct alignas(8) CustomAligned +{ + qint64 v = 0; + CustomAligned() = default; + CustomAligned(qint64 i) : v(i) { } + friend bool operator==(const CustomAligned &x, const CustomAligned &y) { return x.v == y.v; } +}; + +void tst_QList::qtbug_90359() const +{ + // Note: a very special test that could only fail for specific alignments + constexpr bool canFail = (alignof(QArrayData) == 4) && (sizeof(QArrayData) == 12); + if constexpr (!canFail) + qWarning() << "This test will always succeed on this system."; + if constexpr (alignof(CustomAligned) > alignof(std::max_align_t)) + QSKIP("The codepaths tested here wouldn't be executed."); + + const QList<CustomAligned> expected({ 0, 1, 2, 3, 4, 5, 6 }); + QList<CustomAligned> actual; + for (int i = 0; i < 7; ++i) { + actual.append(i); + QCOMPARE(actual.at(i), i); + } + QCOMPARE(actual, expected); +} + QTEST_MAIN(tst_QList) #include "tst_qlist.moc" |