summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2023-04-27 09:40:17 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-04-28 13:37:53 +0000
commit72235540cb5215a7487385eb91f3b13021cce470 (patch)
treef41fee3229276b9d55b2c8936d0a517c6df6bad3
parent0590078d0ce324a821299876412c6e08f3d8a734 (diff)
downloadqtbase-72235540cb5215a7487385eb91f3b13021cce470.tar.gz
QVariant: Fix support for metatypes created by Qt < 6.5
In Qt >= 6.1, < 6.5, a trivially constructible type would have the NeedsDestruction flag set, but it's dtor pointer would have been null. In Qt 6.5, the meaning of the NeedsDestruction flag was changed to be more aligned with what the name suggests, and thus would only be set for non-trivially destructible types. For QMetaType this was fine, but QVariant has a check for acceptable metatypes which attempts to verify whether a QMetaType is usable for QVariant. The check assumes the semantics of Qt 6.5, and thus fails for metatypes created by older Qt versions. To fix this issue, we increment the QMetaType revision field, and only check the metatype's destruction support if the revision is high enough. In theory, that allows passing unsuitable metatypes from older Qt versions to QVariant; however, such code would have been broken in prior Qt releases already (which didn't attempt the check), and no code that used to work in any released Qt version will break (as we simply skip a check that was passing before). Fixes: QTBUG-113227 Change-Id: I12e02bd97d2c410ea1a36efb0ce2389f21d50a30 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit c2f01d4cfb1b144bcc2bf295399ef0d4ad70dae2) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/corelib/kernel/qmetatype.h11
-rw-r--r--src/corelib/kernel/qmetatype_p.h7
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp28
3 files changed, 43 insertions, 3 deletions
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index e70f901a09..a641313c5b 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -246,7 +246,14 @@ using NonConstMetaTypeInterface = const QMetaTypeInterface;
class QMetaTypeInterface
{
public:
- ushort revision; // 0 in Qt 6.0. Can increase if new field are added
+
+ /* Revision: Can increase if new field are added, or if semantics changes
+ 0: Initial Revision
+ 1: the meaning of the NeedsDestruction flag changed
+ */
+ static inline constexpr ushort CurrentRevision = 1;
+
+ ushort revision;
ushort alignment;
uint size;
uint flags;
@@ -2461,7 +2468,7 @@ struct QMetaTypeInterfaceWrapper
using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>;
static inline InterfaceType metaType = {
- /*.revision=*/ 0,
+ /*.revision=*/ QMetaTypeInterface::CurrentRevision,
/*.alignment=*/ alignof(T),
/*.size=*/ sizeof(T),
/*.flags=*/ QMetaTypeForType<T>::Flags,
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index 3defbc70ef..e649394832 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -152,7 +152,12 @@ inline bool isMoveConstructible(const QtPrivate::QMetaTypeInterface *iface) noex
inline bool isDestructible(const QtPrivate::QMetaTypeInterface *iface) noexcept
{
- return checkMetaTypeFlagOrPointer(iface, iface->dtor, QMetaType::NeedsDestruction);
+ /* For metatypes of revision 1, the NeedsDestruction was set even for trivially
+ destructible types, but their dtor pointer would be null.
+ For that reason, we need the additional check here.
+ */
+ return iface->revision < 1 ||
+ checkMetaTypeFlagOrPointer(iface, iface->dtor, QMetaType::NeedsDestruction);
}
inline void defaultConstruct(const QtPrivate::QMetaTypeInterface *iface, void *where)
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index 28eb45660e..32dd168520 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -331,6 +331,7 @@ private slots:
void constructFromIncompatibleMetaType_data();
void constructFromIncompatibleMetaType();
+ void constructFromQtLT65MetaType();
void copyNonDefaultConstructible();
private:
@@ -5636,6 +5637,33 @@ void tst_QVariant::constructFromIncompatibleMetaType()
QVERIFY(!QVariant(regular).convert(type));
}
+void tst_QVariant::constructFromQtLT65MetaType()
+{
+ auto qsizeIface = QtPrivate::qMetaTypeInterfaceForType<QSize>();
+
+ QtPrivate::QMetaTypeInterface qsize64Iface = {
+ /*revision*/0,
+ 8,
+ 8,
+ QMetaType::NeedsConstruction | QMetaType::NeedsDestruction,
+ 0,
+ qsizeIface->metaObjectFn,
+ "FakeQSize",
+ qsizeIface->defaultCtr,
+ qsizeIface->copyCtr,
+ qsizeIface->moveCtr,
+ /*dtor =*/ nullptr,
+ qsizeIface->equals,
+ qsizeIface->lessThan,
+ qsizeIface->debugStream,
+ qsizeIface->dataStreamOut,
+ qsizeIface->dataStreamIn,
+ /*legacyregop =*/ nullptr
+ };
+ QVariant var{ QMetaType(&qsize64Iface) };
+ QVERIFY(var.isValid());
+}
+
void tst_QVariant::copyNonDefaultConstructible()
{
NonDefaultConstructible ndc(42);