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.8
Change-Id: I222806b3804df6272abdfffd45f96312d23be1af
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit eb87b0444ac8fec4d86bc26dc4bec80f82953f7c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2025-02-14 12:46:22 -08:00 committed by Qt Cherry-pick Bot
parent 22f33e1bd2
commit c1bb08ab26
2 changed files with 13 additions and 7 deletions

View File

@ -305,11 +305,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;
}

View File

@ -124,9 +124,8 @@ public:
const void *storage() const
{ return is_shared ? data.shared->data() : &data.data; }
// determine internal storage at compile time
template<typename T> const T &get() const
{ return *static_cast<const T *>(CanUseInternalSpace<T> ? &data.data : data.shared->data()); }
{ return *static_cast<const T *>(storage()); }
inline const QtPrivate::QMetaTypeInterface *typeInterface() const
{
@ -771,7 +770,7 @@ template<typename T> inline T qvariant_cast(QVariant &&v)
{
QMetaType targetType = QMetaType::fromType<T>();
if (v.d.type() == targetType) {
if constexpr (QVariant::Private::CanUseInternalSpace<T>) {
if (!v.d.is_shared) {
return std::move(*reinterpret_cast<T *>(v.d.data.data));
} else {
if (v.d.data.shared->ref.loadRelaxed() == 1)