diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2024-04-22 12:45:34 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-04-23 01:03:34 +0200 |
commit | 37bd19f30102d3e266386e3b81068f2e9cb20425 (patch) | |
tree | eb515f6b046ba9bf2638c5ee291a796fa1d1d300 /src/qml/jsruntime | |
parent | 19b09affee8698f80d386e3b286753974f6bf10a (diff) |
QtQml: Fix some type conversion edge cases
If the type conversion code fails to convert an argument, we still need
to make sure the argument has a definite value. Otherwise we may trigger
undefined behavior somewhere down the line. Furthermore, we want to look
at the precise type when converting list properties. Otherwise we get a
list property without any methods back when converting.
Pick-to: 6.7 6.5 6.2
Change-Id: I012c0360ef1578c768362d5a4648252d3e6803d8
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4jscall_p.h | 28 |
2 files changed, 24 insertions, 15 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index d09dcced19..6b84146866 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -2686,16 +2686,15 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi return true; } - if (metaType == QMetaType::fromType<QQmlListReference>()) { - if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) { + if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) { + if (metaType == QMetaType::fromType<QQmlListReference>()) { *reinterpret_cast<QQmlListReference *>(data) = wrapper->toListReference(); return true; } - } - if (metaType == QMetaType::fromType<QQmlListProperty<QObject>>()) { - if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) { - *reinterpret_cast<QQmlListProperty<QObject> *>(data) = *wrapper->d()->property(); + const auto wrapperPrivate = wrapper->d(); + if (wrapperPrivate->propertyType() == metaType) { + *reinterpret_cast<QQmlListProperty<QObject> *>(data) = *wrapperPrivate->property(); return true; } } diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h index ef4b742590..59f594c939 100644 --- a/src/qml/jsruntime/qv4jscall_p.h +++ b/src/qml/jsruntime/qv4jscall_p.h @@ -125,10 +125,18 @@ ReturnedValue convertAndCall( types[i + 1] = argumentType; if (const qsizetype argumentSize = argumentType.sizeOf()) { Q_ALLOCA_VAR(void, argument, argumentSize); - if (argumentType.flags() & QMetaType::NeedsConstruction) + if (argumentType.flags() & QMetaType::NeedsConstruction) { argumentType.construct(argument); - if (i < argc) - ExecutionEngine::metaTypeFromJS(argv[i], argumentType, argument); + if (i < argc) + ExecutionEngine::metaTypeFromJS(argv[i], argumentType, argument); + } else if (i >= argc + || !ExecutionEngine::metaTypeFromJS(argv[i], argumentType, argument)) { + // If we can't convert the argument, we need to default-construct it even if it + // doesn't formally need construction. + // E.g. an int doesn't need construction, but we still want it to be 0. + argumentType.construct(argument); + } + values[i + 1] = argument; } else { values[i + 1] = nullptr; @@ -201,13 +209,15 @@ bool convertAndCall(ExecutionEngine *engine, QObject *thisObject, // Clear the return value resultType.destruct(result); resultType.construct(result); - } else { + } else if (resultType == QMetaType::fromType<QVariant>()) { // When the return type is QVariant, JS objects are to be returned as // QJSValue wrapped in QVariant. metaTypeFromJS unwraps them, unfortunately. - if (resultType == QMetaType::fromType<QVariant>()) - *static_cast<QVariant *>(result) = ExecutionEngine::toVariant(jsResult, QMetaType {}); - else - ExecutionEngine::metaTypeFromJS(jsResult, resultType, result); + *static_cast<QVariant *>(result) = ExecutionEngine::toVariant(jsResult, QMetaType {}); + } else if (!ExecutionEngine::metaTypeFromJS(jsResult, resultType, result)) { + // If we cannot convert, also clear the return value. + // The caller may have given us an uninitialized QObject*, expecting it to be overwritten. + resultType.destruct(result); + resultType.construct(result); } return !jsResult->isUndefined(); } @@ -276,7 +286,7 @@ inline ReturnedValue coerceListType( } if (listValueType.flags() & QMetaType::PointerToQObject) { - QV4::Scoped<QmlListWrapper> newList(scope, QmlListWrapper::create(engine, listValueType)); + QV4::Scoped<QmlListWrapper> newList(scope, QmlListWrapper::create(engine, type)); QQmlListProperty<QObject> *listProperty = newList->d()->property(); const qsizetype length = array->getLength(); |