diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-02-05 13:18:25 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-02-05 16:21:11 +0000 |
commit | 62bf7be90ba5d7868cc18c8a1e81209c91f449c5 (patch) | |
tree | 4cf6cd79e7a46408b456d567134451b905199711 /tests/auto | |
parent | 41f39169108b1e43ccfca32dc73ceaf16d2a41c8 (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/auto')
-rw-r--r-- | tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp | 42 |
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 4718eb33b4..4bbfaffc1a 100644 --- a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp +++ b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp @@ -68,6 +68,7 @@ private slots: void insertAnimation(); void clear(); void pauseResume(); + void deleteFromListener(); }; void tst_QSequentialAnimationGroupJob::initTestCase() @@ -126,15 +127,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 @@ -1650,6 +1659,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" |