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 Change-Id: I8176a4cc79f100ee772b09425e88fe8ff3ae226a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> (cherry picked from commit 37e26d2b3011acc86bbda1e1f46114d7c8441915) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
3947279d68
commit
a6c6d0bb89
@ -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);
|
||||
|
@ -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.
|
||||
@ -346,6 +346,8 @@ private slots:
|
||||
|
||||
void fromReadOnlyData() const;
|
||||
|
||||
void qtbug_90359() const;
|
||||
|
||||
private:
|
||||
template<typename T> void copyConstructor() const;
|
||||
template<typename T> void add() const;
|
||||
@ -3180,5 +3182,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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user