QmlCompiler: Do not miscompile ID lookups in invalid types
If we cannot resolve a type, we need to assume that all its properties are components and assign separate contexts to all inner objects. Otherwise, if one of them actually is, the attempt to resolve it at run time will crash. Pick-to: 6.8 Fixes: QTBUG-129281 Change-Id: Ic34b5308accdd93f6797ee39fcd56040cf86b1ce Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
724c48f60a
commit
dea8e38d95
|
@ -610,6 +610,12 @@ void QQmlJSImportVisitor::processDefaultProperties()
|
|||
const QQmlJSMetaProperty defaultProp = parentScope->property(defaultPropertyName);
|
||||
auto propType = defaultProp.type();
|
||||
const auto handleUnresolvedDefaultProperty = [&](const QQmlJSScope::ConstPtr &) {
|
||||
|
||||
// Since we don't know the property type, we need to assume it's QQmlComponent and that
|
||||
// IDs from the inner scopes are inaccessible.
|
||||
for (const QQmlJSScope::Ptr &scope : std::as_const(*it))
|
||||
scope->setIsWrappedInImplicitComponent(true);
|
||||
|
||||
// Property type is not fully resolved we cannot tell any more than this
|
||||
m_logger->log(QStringLiteral("Property \"%1\" has incomplete type \"%2\". You may be "
|
||||
"missing an import.")
|
||||
|
@ -735,9 +741,20 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
|
|||
for (const PendingPropertyObjectBinding &objectBinding :
|
||||
std::as_const(m_pendingPropertyObjectBindings)) {
|
||||
const QString propertyName = objectBinding.name;
|
||||
QQmlJSScope::ConstPtr childScope = objectBinding.childScope;
|
||||
QQmlJSScope::Ptr childScope = objectBinding.childScope;
|
||||
|
||||
if (!isTypeResolved(objectBinding.scope)) // guarantees property lookup
|
||||
const auto handleUnresolvedType = [&](const QQmlJSScope::ConstPtr &type) {
|
||||
// Since we don't know the property type we need to assume that it's QQmlComponent and
|
||||
// that IDs from the child scope are inaccessible outside of it.
|
||||
childScope->setIsWrappedInImplicitComponent(true);
|
||||
|
||||
m_logger->log(QStringLiteral("Type %1 is used but it is not resolved")
|
||||
.arg(getScopeName(type, type->scopeType())),
|
||||
qmlUnresolvedType, type->sourceLocation());
|
||||
};
|
||||
|
||||
// guarantees property lookup
|
||||
if (!isTypeResolved(objectBinding.scope, handleUnresolvedType))
|
||||
continue;
|
||||
|
||||
QQmlJSMetaProperty property = objectBinding.scope->property(propertyName);
|
||||
|
@ -748,6 +765,11 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
|
|||
continue;
|
||||
}
|
||||
const auto handleUnresolvedProperty = [&](const QQmlJSScope::ConstPtr &) {
|
||||
|
||||
// Since we don't know the property type we need to assume that it's QQmlComponent and
|
||||
// that IDs from the child scope are inaccessible outside of it.
|
||||
childScope->setIsWrappedInImplicitComponent(true);
|
||||
|
||||
// Property type is not fully resolved we cannot tell any more than this
|
||||
m_logger->log(QStringLiteral("Property \"%1\" has incomplete type \"%2\". You may be "
|
||||
"missing an import.")
|
||||
|
@ -774,7 +796,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
|
|||
continue;
|
||||
}
|
||||
|
||||
objectBinding.childScope->setIsWrappedInImplicitComponent(
|
||||
childScope->setIsWrappedInImplicitComponent(
|
||||
causesImplicitComponentWrapping(property, childScope));
|
||||
|
||||
// unique because it's per-scope and per-property
|
||||
|
|
|
@ -167,6 +167,7 @@ set(qml_files
|
|||
indirectlyShadowable.qml
|
||||
infinities.qml
|
||||
infinitiesToInt.qml
|
||||
insertContextOnInvalidType.qml
|
||||
intEnumCompare.qml
|
||||
intOverflow.qml
|
||||
intToEnum.qml
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import QtQml
|
||||
import Handlerei
|
||||
|
||||
HandleHandler {
|
||||
property var handleDelegateOutter: handleDelegate
|
||||
handle: QtObject { id: handleDelegate }
|
||||
}
|
|
@ -130,6 +130,7 @@ private slots:
|
|||
void infinities();
|
||||
void infinitiesToInt();
|
||||
void innerObjectNonShadowable();
|
||||
void insertContextOnInvalidType();
|
||||
void intEnumCompare();
|
||||
void intOverflow();
|
||||
void intToEnum();
|
||||
|
@ -2475,6 +2476,36 @@ void tst_QmlCppCodegen::innerObjectNonShadowable()
|
|||
QCOMPARE(rootObject->objectName(), u"foo"_s);
|
||||
}
|
||||
|
||||
class HandleHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QQmlComponent *handle MEMBER m_handle)
|
||||
|
||||
private:
|
||||
QQmlComponent *m_handle = nullptr;
|
||||
};
|
||||
|
||||
void tst_QmlCppCodegen::insertContextOnInvalidType()
|
||||
{
|
||||
qmlRegisterType<HandleHandler>("Handlerei", 1, 0, "HandleHandler");
|
||||
|
||||
QQmlEngine engine;
|
||||
QQmlComponent component(&engine, QUrl(u"qrc:/qt/qml/TestTypes/insertContextOnInvalidType.qml"_s));
|
||||
|
||||
QVERIFY2(component.isReady(), qPrintable(component.errorString()));
|
||||
|
||||
QTest::ignoreMessage(
|
||||
QtWarningMsg,
|
||||
"qrc:/qt/qml/TestTypes/insertContextOnInvalidType.qml:5: "
|
||||
"ReferenceError: handleDelegate is not defined");
|
||||
QScopedPointer<QObject> rootObject(component.create());
|
||||
QVERIFY(rootObject);
|
||||
|
||||
const char *outter = "handleDelegateOutter";
|
||||
QVERIFY(rootObject->metaObject()->indexOfProperty(outter) != -1);
|
||||
QVERIFY(!rootObject->property(outter).isValid());
|
||||
}
|
||||
|
||||
void tst_QmlCppCodegen::intEnumCompare()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
|
|
Loading…
Reference in New Issue