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.

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>
(cherry picked from commit c1bb08ab269a2e0e734f9ffe70149e1b480a95e5)
bb10
Thiago Macieira 2025-02-14 12:46:22 -08:00 committed by Qt Cherry-pick Bot
parent 4a97fd2f8e
commit 9760d84262
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)