aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-02-05 13:18:25 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-02-05 16:21:11 +0000
commit2ba30fcc069f63153baeb38cd5c57d5639bdc26b (patch)
tree465f30e0eafce68be09dbb1c0e1e8d5cbf585c6b /tests
parent81b3675a887e692dbcab33deb0a3bed96fb36b21 (diff)
QSequentialAnimationGroupJob: Protect against self-deletion
setCurrentAnimation() can indirectly delete the animation group job itself by invoking the animation controller. Use the RETURN_IF_DELETED mechanism to avoid the resulting dangling pointers. Task-number: QTBUG-90401 Change-Id: Ibd0ad21e8d3af4760604c3ff37dc46101d5f49ad Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 680f28b08f65ad38c8d5498b5738231b2a2779a3) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp42
1 files changed, 41 insertions, 1 deletions
diff --git a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
index 3c6d4f739c..2712ccde67 100644
--- a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
@@ -70,6 +70,7 @@ private slots:
void insertAnimation();
void clear();
void pauseResume();
+ void deleteFromListener();
};
void tst_QSequentialAnimationGroupJob::initTestCase()
@@ -128,15 +129,23 @@ protected:
class StateChangeListener: public QAnimationJobChangeListener
{
public:
- virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
+ virtual void animationStateChanged(
+ QAbstractAnimationJob *job, QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State)
{
states << newState;
+ if (beEvil) {
+ delete job->group();
+ groupDeleted = true;
+ }
}
void clear() { states.clear(); }
int count() const { return states.count(); }
QList<QAbstractAnimationJob::State> states;
+ bool beEvil = false;
+ bool groupDeleted = false;
};
class FinishedListener: public QAnimationJobChangeListener
@@ -1655,6 +1664,37 @@ void tst_QSequentialAnimationGroupJob::uncontrolledWithLoops()
QTRY_COMPARE(group.state(), QAbstractAnimationJob::Stopped);
}
+void tst_QSequentialAnimationGroupJob::deleteFromListener()
+{
+ QSequentialAnimationGroupJob *group = new QSequentialAnimationGroupJob;
+
+ UncontrolledAnimation *uncontrolled = new UncontrolledAnimation();
+ TestAnimation *shortLoop = new TestAnimation(100);
+ UncontrolledAnimation *more = new UncontrolledAnimation();
+
+ shortLoop->setLoopCount(-1);
+
+ group->appendAnimation(uncontrolled);
+ group->appendAnimation(shortLoop);
+ group->appendAnimation(more);
+
+ StateChangeListener listener;
+ listener.beEvil = true;
+ shortLoop->addAnimationChangeListener(&listener, QAbstractAnimationJob::StateChange);
+ group->setLoopCount(2);
+
+ group->start();
+
+ QCOMPARE(group->currentLoop(), 0);
+ QCOMPARE(group->state(), QAbstractAnimationJob::Running);
+ QTRY_COMPARE(uncontrolled->state(), QAbstractAnimationJob::Running);
+
+ QVERIFY(!listener.groupDeleted);
+ uncontrolled->stop();
+
+ QTRY_VERIFY(listener.groupDeleted);
+ // It's dead, Jim.
+}
QTEST_MAIN(tst_QSequentialAnimationGroupJob)
#include "tst_qsequentialanimationgroupjob.moc"