summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTamas Martinec <tamas.martinec@symbio.com>2021-03-25 12:06:20 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-03-26 15:25:52 +0000
commit0ea35a50f02c05a8122ce5b45602698c70efcf79 (patch)
treeefecb35b9aa998356793099c28ad271cb86ea1bd
parent3ec9a4ad692734bdbb07206d23a3e607ccd89d4c (diff)
Qt SCXML: Fix HistoryState crash
Use the initial state of the parent state as the transition of a history state, if the parent state of the history state was not entered before. Task-number: QTBUG-89845 Fixes: QTBUG-76091 Change-Id: I4c8a5898406bdf2931424b3cf012e42e422431ae Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit e868c6fa904a2b31b253c07739564fc9e7f1b76c) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/scxml/qscxmlstatemachine.cpp12
-rw-r--r--tests/auto/compiled/CMakeLists.txt1
-rw-r--r--tests/auto/compiled/historyState.scxml57
-rw-r--r--tests/auto/compiled/tst_compiled.cpp16
4 files changed, 84 insertions, 2 deletions
diff --git a/src/scxml/qscxmlstatemachine.cpp b/src/scxml/qscxmlstatemachine.cpp
index a875a53..d90caa7 100644
--- a/src/scxml/qscxmlstatemachine.cpp
+++ b/src/scxml/qscxmlstatemachine.cpp
@@ -1247,7 +1247,15 @@ void QScxmlStateMachinePrivate::addDescendantStatesToEnter(
addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry,
defaultHistoryContent);
} else {
- const auto transitionIdx = m_stateTable->array(state.transitions)[0];
+ int transitionIdx = StateTable::InvalidIndex;
+ if (state.transitions == StateTable::InvalidIndex) {
+ int parentInitialTransition = m_stateTable->state(state.parent).initialTransition;
+ if (parentInitialTransition == StateTable::InvalidIndex)
+ return;
+ transitionIdx = parentInitialTransition;
+ } else {
+ transitionIdx = m_stateTable->array(state.transitions)[0];
+ }
const auto &defaultHistoryTransition = m_stateTable->transition(transitionIdx);
defaultHistoryContent->operator[](state.parent) =
defaultHistoryTransition.transitionInstructions;
@@ -1457,7 +1465,7 @@ void QScxmlStateMachinePrivate::getEffectiveTargetStates(OrderedSet *targets,
for (int historyState : historyValueIter.value()) {
targets->add(historyState);
}
- } else {
+ } else if (state.transitions != StateTable::InvalidIndex) {
getEffectiveTargetStates(targets, m_stateTable->array(state.transitions)[0]);
}
} else {
diff --git a/tests/auto/compiled/CMakeLists.txt b/tests/auto/compiled/CMakeLists.txt
index 39ceb72..1a22044 100644
--- a/tests/auto/compiled/CMakeLists.txt
+++ b/tests/auto/compiled/CMakeLists.txt
@@ -39,6 +39,7 @@ qt6_add_statecharts(tst_compiled
initialhistory.scxml
connection.scxml
topmachine.scxml
+ historyState.scxml
)
#### Keys ignored in scope 1:.:.:compiled.pro:<TRUE>:
diff --git a/tests/auto/compiled/historyState.scxml b/tests/auto/compiled/historyState.scxml
new file mode 100644
index 0000000..c1f58ad
--- /dev/null
+++ b/tests/auto/compiled/historyState.scxml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" binding="early" xmlns:qt="http://www.qt.io/2015/02/scxml-ext" name="HistoryState" qt:editorversion="4.9.0">
+ <state id="Off">
+ <transition type="external" event="toOn" target="On">
+ </transition>
+ <transition type="external" event="toHistory" target="History_1">
+ </transition>
+ <onentry>
+ <log label="Off" expr="onentry"/>
+ </onentry>
+ <onexit>
+ <log label="Off" expr="onexit"/>
+ </onexit>
+ </state>
+ <state id="On" initial="Beta">
+ <state id="Alpha">
+ <transition type="external" event="toBeta" target="Beta">
+ </transition>
+ <onentry>
+ <log label="Alpha" expr="onentry"/>
+ </onentry>
+ <onexit>
+ <log label="Alpha" expr="onexit"/>
+ </onexit>
+ </state>
+ <state id="Beta">
+ <transition type="external" event="toDelta" target="Delta">
+ </transition>
+ <onentry>
+ <log label="Beta" expr="onentry"/>
+ </onentry>
+ <onexit>
+ <log label="Beta" expr="onexit"/>
+ </onexit>
+ </state>
+ <history type="shallow" id="History_1">
+ </history>
+ <state id="Delta">
+ <transition type="external" event="toAlpha" target="Alpha">
+ </transition>
+ <onentry>
+ <log label="Delta" expr="onentry"/>
+ </onentry>
+ <onexit>
+ <log label="Delta" expr="onexit"/>
+ </onexit>
+ </state>
+ <transition type="external" event="toOff" target="Off">
+ </transition>
+ <onentry>
+ <log label="On" expr="onentry"/>
+ </onentry>
+ <onexit>
+ <log label="On" expr="onexit"/>
+ </onexit>
+ </state>
+</scxml>
diff --git a/tests/auto/compiled/tst_compiled.cpp b/tests/auto/compiled/tst_compiled.cpp
index 3d6c071..a99688b 100644
--- a/tests/auto/compiled/tst_compiled.cpp
+++ b/tests/auto/compiled/tst_compiled.cpp
@@ -39,6 +39,7 @@
#include "eventnames1.h"
#include "connection.h"
#include "topmachine.h"
+#include "historyState.h"
enum { SpyWaitTime = 8000 };
@@ -56,6 +57,7 @@ private Q_SLOTS:
void topMachine();
void topMachineDynamic();
void publicSignals();
+ void historyState();
};
void tst_Compiled::stateNames()
@@ -306,6 +308,20 @@ void tst_Compiled::publicSignals()
QCOMPARE(aChanged.access(), QMetaMethod::Public);
}
+void tst_Compiled::historyState()
+{
+ HistoryState historyStateSM;
+ QSignalSpy stableStateSpy(&historyStateSM, SIGNAL(reachedStableState()));
+ historyStateSM.start();
+
+ stableStateSpy.wait(5000);
+ QCOMPARE(historyStateSM.activeStateNames(), QStringList(QLatin1String("Off")));
+
+ historyStateSM.submitEvent("toHistory");
+ stableStateSpy.wait(5000);
+ QCOMPARE(historyStateSM.activeStateNames(), QStringList(QLatin1String("Beta")));
+}
+
QTEST_MAIN(tst_Compiled)
#include "tst_compiled.moc"