aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-06-14 10:54:50 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-06-15 11:57:32 +0000
commita2104034d404179f5fad98fd54a133b288ded47d (patch)
tree7efcd2510ce8481a0e14ac6a665c0f384889ad61 /src
parent0c50edd6f5a819a7bc6e19c5ac69191d491167da (diff)
QML: Try QML conversion before metatype conversion
and guard against null gadgetPtr. This is what we get for uninitialized value type properties. Pick-to: 6.5 6.5.2 6.6 Fixes: QTBUG-114494 Change-Id: I86ad23abcc4fec219017d1aad6b7add1c9a9af5d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp24
-rw-r--r--src/qml/qml/qqmlglobal.cpp86
-rw-r--r--src/qml/qml/qqmlglobal_p.h4
3 files changed, 69 insertions, 45 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index e34c22b8e2..77664c00c6 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -2662,8 +2662,23 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
const QMetaType valueType = vtw->type();
if (valueType == metaType)
return vtw->toGadget(data);
- if (QMetaType::canConvert(valueType, metaType))
- return QMetaType::convert(valueType, vtw->d()->gadgetPtr(), metaType, data);
+
+ Heap::QQmlValueTypeWrapper *d = vtw->d();
+ if (d->isReference())
+ d->readReference();
+
+ if (void *gadgetPtr = d->gadgetPtr()) {
+ if (QQmlValueTypeProvider::createValueType(metaType, data, valueType, gadgetPtr))
+ return true;
+ if (QMetaType::canConvert(valueType, metaType))
+ return QMetaType::convert(valueType, gadgetPtr, metaType, data);
+ } else {
+ QVariant empty(valueType);
+ if (QQmlValueTypeProvider::createValueType(metaType, data, valueType, empty.data()))
+ return true;
+ if (QMetaType::canConvert(valueType, metaType))
+ return QMetaType::convert(valueType, empty.data(), metaType, data);
+ }
}
// Try to use magic; for compatibility with qjsvalue_cast.
@@ -2676,7 +2691,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
if (variantObject) {
// Actually a reference, because we're poking it for its data() below and we want
// the _original_ data, not some copy.
- const QVariant &var = variantObject->d()->data();
+ QVariant &var = variantObject->d()->data();
if (var.metaType() == metaType) {
metaType.destruct(data);
@@ -2725,7 +2740,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
proto = proto->getPrototypeOf();
}
}
- } else if (QQmlValueTypeProvider::createValueType(metaType, data, var)) {
+ } else if (QQmlValueTypeProvider::createValueType(
+ metaType, data, var.metaType(), var.data())) {
return true;
}
} else if (value.isNull() && isPointer) {
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index e2ca8f873f..3759983b7a 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -115,30 +115,33 @@ static bool fromMatchingType(
const QMetaType parameterType = ctor.parameterMetaType(0);
- QVariant source = retrieve(parameterType);
- const QMetaType sourceMetaType = source.metaType();
- if (sourceMetaType == parameterType) {
- callConstructor(targetMetaObject, i, source.data(), allocate());
- return true;
- }
-
- if (const QMetaObject *parameterMetaObject = parameterType.metaObject()) {
- if (const QMetaObject *sourceMetaObject = sourceMetaType.metaObject();
- sourceMetaObject && sourceMetaObject->inherits(parameterMetaObject)) {
- // Allow construction from derived types.
- callConstructor(targetMetaObject, i, source.data(), allocate());
+ if (retrieve(parameterType, [&](QMetaType sourceMetaType, void *sourceData) {
+ if (sourceMetaType == parameterType) {
+ callConstructor(targetMetaObject, i, sourceData, allocate());
return true;
}
- }
- // Do not recursively try to create parameters here. This may end up in infinite recursion.
+ if (const QMetaObject *parameterMetaObject = parameterType.metaObject()) {
+ if (const QMetaObject *sourceMetaObject = sourceMetaType.metaObject();
+ sourceMetaObject && sourceMetaObject->inherits(parameterMetaObject)) {
+ // Allow construction from derived types.
+ callConstructor(targetMetaObject, i, sourceData, allocate());
+ return true;
+ }
+ }
+
+ // Do not recursively try to create parameters here. This may end up in infinite recursion.
- // At this point, s should be a builtin type. For builtin types
- // the QMetaType converters are good enough.
- QVariant converted(parameterType);
- if (QMetaType::convert(sourceMetaType, source.constData(),
- parameterType, converted.data())) {
- callConstructor(targetMetaObject, i, converted.data(), allocate());
+ // At this point, s should be a builtin type. For builtin types
+ // the QMetaType converters are good enough.
+ QVariant converted(parameterType);
+ if (QMetaType::convert(sourceMetaType, sourceData, parameterType, converted.data())) {
+ callConstructor(targetMetaObject, i, converted.data(), allocate());
+ return true;
+ }
+
+ return false;
+ })) {
return true;
}
}
@@ -151,8 +154,10 @@ static bool fromMatchingType(
const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate)
{
return fromMatchingType(
- targetMetaObject, std::forward<Allocate>(allocate), [&](QMetaType parameterType) {
- return QV4::ExecutionEngine::toVariant(source, parameterType);
+ targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType parameterType, auto callback) {
+ QVariant variant = QV4::ExecutionEngine::toVariant(source, parameterType);
+ return callback(variant.metaType(), variant.data());
});
}
@@ -160,8 +165,9 @@ template<typename Allocate>
static bool fromMatchingType(
const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate)
{
- return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), [&](QMetaType) {
- return source;
+ return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType, auto callback) {
+ return callback(source.metaType(), source.data());
});
}
@@ -491,12 +497,12 @@ bool QQmlValueTypeProvider::createValueType(
}
bool QQmlValueTypeProvider::createValueType(
- QMetaType targetMetaType, void *target, const QVariant &source)
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source)
{
- if (source.metaType() == QMetaType::fromType<QJSValue>()) {
- QJSValue val = source.value<QJSValue>();
+ if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
+ const QJSValue *val = static_cast<const QJSValue *>(source);
return createValueType(
- targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(&val)));
+ targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
}
if (!isConstructibleMetaType(targetMetaType))
@@ -518,39 +524,39 @@ bool QQmlValueTypeProvider::createValueType(
if (type.canPopulateValueType()) {
if (const QMetaObject *sourceMetaObject
- = QQmlMetaType::metaObjectForValueType(source.metaType())) {
+ = QQmlMetaType::metaObjectForValueType(sourceMetaType)) {
doWriteProperties(
targetMetaObject, target, sourceMetaObject,
[&source](const QMetaObject *sourceMetaObject, int sourceProperty) {
- return sourceMetaObject->property(sourceProperty).readOnGadget(
- source.constData());
+ return sourceMetaObject->property(sourceProperty).readOnGadget(source);
});
return true;
}
- if (source.metaType() == QMetaType::fromType<QVariantMap>()) {
+ if (sourceMetaType == QMetaType::fromType<QVariantMap>()) {
doWriteProperties(
- targetMetaObject, target,
- *static_cast<const QVariantMap *>(source.constData()));
+ targetMetaObject, target, *static_cast<const QVariantMap *>(source));
return true;
}
- if (source.metaType() == QMetaType::fromType<QVariantHash>()) {
+ if (sourceMetaType == QMetaType::fromType<QVariantHash>()) {
doWriteProperties(
- targetMetaObject, target,
- *static_cast<const QVariantHash *>(source.constData()));
+ targetMetaObject, target, *static_cast<const QVariantHash *>(source));
return true;
}
- if (source.metaType().flags() & QMetaType::PointerToQObject) {
- doWriteProperties(targetMetaObject, target, source.value<QObject *>());
+ if (sourceMetaType.flags() & QMetaType::PointerToQObject) {
+ doWriteProperties(targetMetaObject, target, *static_cast<QObject *const *>(source));
return true;
}
}
if (type.canConstructValueType()) {
- if (fromMatchingType(targetMetaObject, source, destruct))
+ if (fromMatchingType(targetMetaObject, destruct, [&](QMetaType, auto callback) {
+ return callback(sourceMetaType, source);
+ })) {
return true;
+ }
warn();
}
}
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 95403d041a..bb710b059d 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -205,7 +205,9 @@ class QQmlValueTypeProvider
{
public:
static bool createValueType(QMetaType targetMetaType, void *target, const QV4::Value &source);
- static bool createValueType(QMetaType targetMetaType, void *target, const QVariant &source);
+ static bool createValueType(
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source);
+
static QVariant constructValueType(
QMetaType targetMetaType, const QMetaObject *targetMetaObject,
int ctorIndex, void *ctorArg);