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 <marc.mutz@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Thiago Macieira 2025-02-14 12:46:22 -08:00
parent 6ea2657ad5
commit eb87b0444a
2 changed files with 13 additions and 7 deletions

View File

@ -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;
}

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
{
@ -761,7 +760,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)