aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-01-29 16:40:58 +0100
committerUlf Hermann <ulf.hermann@qt.io>2024-01-30 17:14:09 +0100
commit7ce3ce41b8cc657d31ee28de73d2962a149cd776 (patch)
tree30ef7efe143de2e597c4cb6bff1bc1ea51e13875
parentdb8ae307ad452cef64443eee1ff4b82f957e169c (diff)
QtQuick: Do not crash on broken states
States can be nullptr these days. Ideally we'd warn about this, but for picking back to 6.5 it's enough to restore the pre-6.5.3 behavior and not crash. Amends commit f905876d6c3abda34dfd85cd40e300a31c1ebe52. Pick-to: 6.7 6.6 6.5 Fixes: QTBUG-120301 Change-Id: I87021eb2dcbe7fc49f37c5d949d79466ae341a1c Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/quick/util/qquickstategroup.cpp38
-rw-r--r--tests/auto/quick/qquickstates/data/broken.qml5
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp16
3 files changed, 44 insertions, 15 deletions
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index 9a469b8112..a111d4b543 100644
--- a/src/quick/util/qquickstategroup.cpp
+++ b/src/quick/util/qquickstategroup.cpp
@@ -181,19 +181,25 @@ void QQuickStateGroupPrivate::replace_states(QQmlListProperty<QQuickState> *list
if (oldState != state) {
if (oldState)
oldState->setStateGroup(nullptr);
- state->setStateGroup(self);
+
+ if (state)
+ state->setStateGroup(self);
d->states.replace(index, state);
if (!oldState || d->currentState == oldState->name())
- d->setCurrentStateInternal(state->name(), true);
+ d->setCurrentStateInternal(state ? state->name() : QString(), true);
}
}
void QQuickStateGroupPrivate::removeLast_states(QQmlListProperty<QQuickState> *list)
{
auto *d = static_cast<QQuickStateGroup *>(list->object)->d_func();
- if (d->currentState == d->states.last()->name())
- d->setCurrentStateInternal(d->states.size() > 1 ? d->states.first()->name() : QString(), true);
- d->states.last()->setStateGroup(nullptr);
+ if (QQuickState *last = d->states.last()) {
+ if (d->currentState == last->name()) {
+ QQuickState *first = d->states.size() > 1 ? d->states.first() : nullptr;
+ d->setCurrentStateInternal(first ? first->name() : QString(), true);
+ }
+ last->setStateGroup(nullptr);
+ }
d->states.removeLast();
}
@@ -304,6 +310,9 @@ void QQuickStateGroup::componentComplete()
names.reserve(d->states.size());
for (int ii = 0; ii < d->states.size(); ++ii) {
QQuickState *state = d->states.at(ii);
+ if (!state)
+ continue;
+
if (!state->isNamed())
state->setName(QLatin1String("anonymousState") + QString::number(++d->unnamedCount));
@@ -342,7 +351,7 @@ bool QQuickStateGroupPrivate::updateAutoState()
bool revert = false;
for (int ii = 0; ii < states.size(); ++ii) {
QQuickState *state = states.at(ii);
- if (state->isWhenKnown()) {
+ if (state && state->isWhenKnown()) {
if (state->isNamed()) {
bool whenValue = state->when();
const QQmlPropertyIndex whenIndex(state->metaObject()->indexOfProperty("when"));
@@ -477,9 +486,9 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state,
QQuickState *oldState = nullptr;
if (!currentState.isEmpty()) {
- for (int ii = 0; ii < states.size(); ++ii) {
- if (states.at(ii)->name() == currentState) {
- oldState = states.at(ii);
+ for (QQuickState *state : std::as_const(states)) {
+ if (state && state->name() == currentState) {
+ oldState = state;
break;
}
}
@@ -489,9 +498,9 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state,
emit q->stateChanged(currentState);
QQuickState *newState = nullptr;
- for (int ii = 0; ii < states.size(); ++ii) {
- if (states.at(ii)->name() == currentState) {
- newState = states.at(ii);
+ for (QQuickState *state : std::as_const(states)) {
+ if (state && state->name() == currentState) {
+ newState = state;
break;
}
}
@@ -513,9 +522,8 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state,
QQuickState *QQuickStateGroup::findState(const QString &name) const
{
Q_D(const QQuickStateGroup);
- for (int i = 0; i < d->states.size(); ++i) {
- QQuickState *state = d->states.at(i);
- if (state->name() == name)
+ for (QQuickState *state : std::as_const(d->states)) {
+ if (state && state->name() == name)
return state;
}
diff --git a/tests/auto/quick/qquickstates/data/broken.qml b/tests/auto/quick/qquickstates/data/broken.qml
new file mode 100644
index 0000000000..8813c8bb39
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/broken.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+ states: ["test"]
+}
diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
index 8d010595b5..be1361e4ab 100644
--- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp
+++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
@@ -191,6 +191,7 @@ private slots:
void rewindAnchorChange();
void rewindAnchorChangeSize();
void bindingProperlyRemovedWithTransition();
+ void doNotCrashOnBroken();
};
void tst_qquickstates::initTestCase()
@@ -2036,6 +2037,21 @@ void tst_qquickstates::bindingProperlyRemovedWithTransition()
QTRY_COMPARE(item->width(), 100);
}
+void tst_qquickstates::doNotCrashOnBroken()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("broken.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> root(c.create());
+ QVERIFY(root);
+ QQuickItem *item = qobject_cast<QQuickItem *>(root.get());
+ QVERIFY(item);
+
+ QQmlListReference states(item, "states");
+ QCOMPARE(states.size(), 1);
+ QCOMPARE(states.at(0), nullptr);
+}
+
QTEST_MAIN(tst_qquickstates)
#include "tst_qquickstates.moc"