From 37bd19f30102d3e266386e3b81068f2e9cb20425 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 22 Apr 2024 12:45:34 +0200 Subject: 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 --- src/qml/jsruntime/qv4engine.cpp | 11 +++++------ src/qml/jsruntime/qv4jscall_p.h | 28 +++++++++++++++++++--------- 2 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src/qml/jsruntime') 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()) { - if (const QV4::QmlListWrapper *wrapper = value.as()) { + if (const QV4::QmlListWrapper *wrapper = value.as()) { + if (metaType == QMetaType::fromType()) { *reinterpret_cast(data) = wrapper->toListReference(); return true; } - } - if (metaType == QMetaType::fromType>()) { - if (const QV4::QmlListWrapper *wrapper = value.as()) { - *reinterpret_cast *>(data) = *wrapper->d()->property(); + const auto wrapperPrivate = wrapper->d(); + if (wrapperPrivate->propertyType() == metaType) { + *reinterpret_cast *>(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()) { // 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()) - *static_cast(result) = ExecutionEngine::toVariant(jsResult, QMetaType {}); - else - ExecutionEngine::metaTypeFromJS(jsResult, resultType, result); + *static_cast(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 newList(scope, QmlListWrapper::create(engine, listValueType)); + QV4::Scoped newList(scope, QmlListWrapper::create(engine, type)); QQmlListProperty *listProperty = newList->d()->property(); const qsizetype length = array->getLength(); -- cgit v1.2.3