diff --git a/qt6-qtdeclarative.spec b/qt6-qtdeclarative.spec index bd2ae71..f95fa29 100644 --- a/qt6-qtdeclarative.spec +++ b/qt6-qtdeclarative.spec @@ -17,7 +17,7 @@ Summary: Qt6 - QtDeclarative component Name: qt6-%{qt_module} Version: 6.7.1 -Release: 2%{?dist} +Release: 3%{?dist} License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0 Url: http://www.qt.io @@ -35,6 +35,8 @@ Source0: https://download.qt.io/official_releases/qt/%{majmin}/%{version}/submod Source5: qv4global_p-multilib.h ## upstream patches +# https://codereview.qt-project.org/c/qt/qtdeclarative/+/550241 +Patch0: qtdeclarative-avoid-asserts-during-dom-construction.patch ## upstreamable patches @@ -396,6 +398,10 @@ make check -k -C tests ||: %endif %changelog +* Thu Jun 06 2024 Jan Grulich - 6.7.1-3 +- Backport upstream fix - dom: avoid asserts during dom construction + Resolves: RHEL-36430 + * Tue Jun 04 2024 Jan Grulich - 6.7.1-2 - Add rpminspect.yaml Resolves: RHEL-36430 diff --git a/qtdeclarative-avoid-asserts-during-dom-construction.patch b/qtdeclarative-avoid-asserts-during-dom-construction.patch new file mode 100644 index 0000000..8cc611f --- /dev/null +++ b/qtdeclarative-avoid-asserts-during-dom-construction.patch @@ -0,0 +1,352 @@ +From 3ed063d2ff6b418e8487bea0d839fd2f768c91b6 Mon Sep 17 00:00:00 2001 +From: Sami Shalayel +Date: Thu, 21 Mar 2024 14:43:19 +0100 +Subject: [PATCH] dom: avoid asserts during dom construction + +Add missing safeguards to avoid crashing when constructing the Dom, also +add some tests. + +Fixes: QTBUG-123871 +Change-Id: Ie5da7c3b7bbf61d49d755ec6c338e2011532e89b +(cherry picked from commit 4c4605be79e564921699a065df58333d3ee10d59) +Reviewed-by: Fabian Kosmale +--- + +diff --git a/src/qmldom/qqmldomastcreator.cpp b/src/qmldom/qqmldomastcreator.cpp +index 1f5db5a..d8e7590 100644 +--- a/src/qmldom/qqmldomastcreator.cpp ++++ b/src/qmldom/qqmldomastcreator.cpp +@@ -495,8 +495,10 @@ + { + if (auto &lastEl = currentNode(); lastEl.kind == DomType::Binding) { + Binding &b = std::get(lastEl.value); +- if (m_enableScriptExpressions && scriptNodeStack.size() != 1) ++ if (m_enableScriptExpressions ++ && (scriptNodeStack.size() != 1 || scriptNodeStack.last().isList())) { + Q_SCRIPTELEMENT_DISABLE(); ++ } + if (m_enableScriptExpressions) { + b.scriptExpressionValue()->setScriptElement(finalizeScriptExpression( + currentScriptNodeEl().takeVariant(), Path().field(Fields::scriptElement), +@@ -1077,7 +1079,7 @@ + if (!m_enableScriptExpressions) + return false; + +- if (scriptNodeStack.empty()) { ++ if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) { + Q_SCRIPTELEMENT_DISABLE(); + return false; + } +@@ -1106,7 +1108,7 @@ + for (auto it = list; it; it = it->next) { + if (it->elision) { + Node::accept(it->elision, this); +- if (scriptNodeStack.empty()) { ++ if (scriptNodeStack.empty() || !scriptNodeStack.last().isList()) { + Q_SCRIPTELEMENT_DISABLE(); + return false; + } +@@ -1115,7 +1117,7 @@ + } + if (it->element) { + Node::accept(it->element, this); +- if (scriptNodeStack.empty()) { ++ if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) { + Q_SCRIPTELEMENT_DISABLE(); + return false; + } +@@ -1142,7 +1144,7 @@ + Node::accept(it->property, this); + if (!m_enableScriptExpressions) + return false; +- if (scriptNodeStack.empty()) { ++ if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) { + Q_SCRIPTELEMENT_DISABLE(); + return false; + } +@@ -1346,7 +1348,7 @@ + auto current = makeScriptList(list); + + for (auto it = list; it; it = it->next) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current.append(scriptNodeStack.takeLast().takeVariant()); + } + +@@ -1364,15 +1366,15 @@ + + void QQmlDomAstCreator::endVisit(AST::BinaryExpression *exp) + { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.size() < 2); +- + if (!m_enableScriptExpressions) + return; + + auto current = makeScriptElement(exp); + current->addLocation(OperatorTokenRegion, exp->operatorToken); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setRight(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setLeft(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + +@@ -1426,19 +1428,19 @@ + current->addLocation(FileLocationRegion::RightParenthesisRegion, forStatement->rparenToken); + + if (forStatement->statement) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setBody(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode(std::nullopt); + } + + if (forStatement->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setExpression(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode(std::nullopt); + } + + if (forStatement->condition) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setCondition(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode(std::nullopt); + } +@@ -1458,7 +1460,7 @@ + } + + if (forStatement->initialiser) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setInitializer(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode(std::nullopt); + } +@@ -1590,7 +1592,7 @@ + Node::accept(it->declaration, this); + if (!m_enableScriptExpressions) + return false; +- if (scriptNodeStack.empty()) { ++ if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) { + Q_SCRIPTELEMENT_DISABLE(); + return false; + } +@@ -1697,18 +1699,18 @@ + current->addLocation(ElseKeywordRegion, ifStatement->elseToken); + + if (ifStatement->ko) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setAlternative(scriptNodeStack.last().takeVariant()); + scriptNodeStack.removeLast(); + } + + if (ifStatement->ok) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setConsequence(scriptNodeStack.last().takeVariant()); + scriptNodeStack.removeLast(); + } + if (ifStatement->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setCondition(scriptNodeStack.last().takeVariant()); + scriptNodeStack.removeLast(); + } +@@ -1733,7 +1735,7 @@ + current->addLocation(ReturnKeywordRegion, returnStatement->returnToken); + + if (returnStatement->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setExpression(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -1759,7 +1761,7 @@ + current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->dotToken); + + if (expression->base) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setLeft(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -1790,7 +1792,7 @@ + current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->lbracketToken); + + if (expression->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + // if scriptNodeStack.last() is fieldmember expression, add expression to it instead of + // creating new one + current->setRight(currentScriptNodeEl().takeVariant()); +@@ -1798,7 +1800,7 @@ + } + + if (expression->base) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->setLeft(currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -1834,7 +1836,7 @@ + } + + if (exp->base) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -1924,7 +1926,7 @@ + return; + + if (exp->name) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::name, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -2038,7 +2040,7 @@ + } + + if (exp->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -2062,7 +2064,7 @@ + auto current = makeScriptList(list); + + for (auto it = list; it; it = it->next) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current.append(scriptNodeStack.takeLast().takeVariant()); + } + +@@ -2094,7 +2096,7 @@ + } + + if (exp->defaultClause) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -2125,12 +2127,12 @@ + current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken); + + if (exp->block) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } + if (exp->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -2157,13 +2159,13 @@ + current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken); + + if (exp->statement) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::body, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } + + if (exp->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -2191,13 +2193,13 @@ + current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken); + + if (exp->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } + + if (exp->statement) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::body, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +@@ -2224,18 +2226,18 @@ + current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken); + + if (exp->statement) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::body, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } + if (exp->expression) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } + + if (exp->lhs) { +- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty()); ++ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()); + current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant()); + removeCurrentScriptNode({}); + } +diff --git a/tests/auto/qmldom/domdata/domitem/crashes/lambda.qml b/tests/auto/qmldom/domdata/domitem/crashes/lambda.qml +new file mode 100644 +index 0000000..85f696f +--- /dev/null ++++ b/tests/auto/qmldom/domdata/domitem/crashes/lambda.qml +@@ -0,0 +1,7 @@ ++import QtQuick.Controls ++ ++Action { ++ onTriggered: foo(Bla.Bar, function() { ++ console.log("Hello") ++ }) ++} +diff --git a/tests/auto/qmldom/domdata/domitem/crashes/templateStrings.qml b/tests/auto/qmldom/domdata/domitem/crashes/templateStrings.qml +new file mode 100644 +index 0000000..feb5646 +--- /dev/null ++++ b/tests/auto/qmldom/domdata/domitem/crashes/templateStrings.qml +@@ -0,0 +1,10 @@ ++import QtQuick ++ ++ ++Item { ++ property string verbatim1: 'A "verbatim" string!' ++ property string verbatim2: "A 'verbatim' string\u2757" ++ property string verbatim3: `400 + 300 is ${400 + 300}. ++ ++mutliline` ++} +diff --git a/tests/auto/qmldom/domitem/tst_qmldomitem.h b/tests/auto/qmldom/domitem/tst_qmldomitem.h +index 184dc8e..3673871 100644 +--- a/tests/auto/qmldom/domitem/tst_qmldomitem.h ++++ b/tests/auto/qmldom/domitem/tst_qmldomitem.h +@@ -2813,6 +2813,12 @@ + + QTest::addRow("inactiveVisitorMarkerCrash") + << baseDir + u"/inactiveVisitorMarkerCrash.qml"_s; ++ ++ QTest::addRow("templateStrings") ++ << baseDir + u"/crashes/templateStrings.qml"_s; ++ ++ QTest::addRow("lambda") ++ << baseDir + u"/crashes/lambda.qml"_s; + } + void crashes() + {