From eb87b0444ac8fec4d86bc26dc4bec80f82953f7c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 14 Feb 2025 12:46:22 -0800 Subject: [PATCH] QVariant: don't use the static CanUseInternalSpace with existing objects It's possible for the QVariant to have been created by an older or newer build of the library in question in which the type in question was relocatable but has ceased to be, or wasn't relocatable but now is. [ChangeLog][QtCore][QVariant] Fixed a bug where QVariant could misbehave regarding types that changed from non-relocatable to relocatable (or vice-versa) and not all uses of it were recompiled. To benefit from this fix, applications must be recompiled, but they will be safe going forward. Pick-to: 6.9 6.8 Change-Id: I222806b3804df6272abdfffd45f96312d23be1af Reviewed-by: Marc Mutz Reviewed-by: Fabian Kosmale --- src/corelib/kernel/qvariant.cpp | 15 +++++++++++---- src/corelib/kernel/qvariant.h | 5 ++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index bea7ed8963c..b1635c9a3c9 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -293,11 +293,18 @@ static QVariant::Private clonePrivate(const QVariant::Private &other) if (d.is_shared) { d.data.shared->ref.ref(); } else if (const QtPrivate::QMetaTypeInterface *iface = d.typeInterface()) { - Q_ASSERT(d.canUseInternalSpace(iface)); + if (Q_LIKELY(d.canUseInternalSpace(iface))) { + // if not trivially copyable, ask to copy (if it's trivially + // copyable, we've already copied it) + if (iface->copyCtr) + QtMetaTypePrivate::copyConstruct(iface, d.data.data, other.data.data); + } else { + // highly unlikely, but possible case: type has changed relocatability + // between builds + d.data.shared = QVariant::PrivateShared::create(iface->size, iface->alignment); + QtMetaTypePrivate::copyConstruct(iface, d.data.shared->data(), other.data.data); + } - // if not trivially copyable, ask to copy - if (iface->copyCtr) - QtMetaTypePrivate::copyConstruct(iface, d.data.data, other.data.data); } return d; } diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 3bae8e1ab1a..31f5869c9d9 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -124,9 +124,8 @@ public: const void *storage() const { return is_shared ? data.shared->data() : &data.data; } - // determine internal storage at compile time template const T &get() const - { return *static_cast(CanUseInternalSpace ? &data.data : data.shared->data()); } + { return *static_cast(storage()); } inline const QtPrivate::QMetaTypeInterface *typeInterface() const { @@ -761,7 +760,7 @@ template inline T qvariant_cast(QVariant &&v) { QMetaType targetType = QMetaType::fromType(); if (v.d.type() == targetType) { - if constexpr (QVariant::Private::CanUseInternalSpace) { + if (!v.d.is_shared) { return std::move(*reinterpret_cast(v.d.data.data)); } else { if (v.d.data.shared->ref.loadRelaxed() == 1)