summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis du Verdier <louis.du.verdier@free.fr>2018-04-02 20:25:37 +0200
committerLouis du Verdier <louis.du.verdier@free.fr>2018-05-08 16:19:45 +0000
commita609554c031fd57d9a2a3905f5a02cc6b4aa19e9 (patch)
tree22a56bc1cd7a67f447a5a67746376fc5776047e9
parentbdbf6a53c0ab8a7f6ea5586767a6ed818e3d555e (diff)
Fix crash when changing the source of AnimatedImage after a frame change
QMovie emits the signals updated() and frameChanged(), and restarts right after its timer to prepare for the next frame. Since AnimatedImage destroys its underlying QMovie when its source changes, the lines after emit frameChanged() in QMovie will use free'd memory and will most of the time produce a crash. This fix delays the destruction of the underlying QMovie of AnimatedImage using deleteLater() to prevent this kind of behavior from happening without impact/behavior change in the code of QMovie. Unit tests added as well to cover this situation. This commit also fixes a similar crash when Component.onCompleted is called and when the source changes in the associated callback. Task-number: QTBUG-67427 Change-Id: Ic6568a1bc251e5fa2ee1cf8e5f50eaa56c3007db Reviewed-by: VaL Doroshchuk <valentyn.doroshchuk@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Louis du Verdier <louis.du.verdier@free.fr>
-rw-r--r--src/quick/items/qquickanimatedimage.cpp16
-rw-r--r--tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp28
2 files changed, 39 insertions, 5 deletions
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index 26dfdb07a6..075c4a7d72 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -426,15 +426,18 @@ void QQuickAnimatedImage::movieRequestFinished()
}
bool pausedAtStart = d->paused;
- if (d->playing)
+ if (d->movie && d->playing)
d->movie->start();
- if (pausedAtStart)
+ if (d->movie && pausedAtStart)
d->movie->setPaused(true);
- if (d->paused || !d->playing) {
+ if (d->movie && (d->paused || !d->playing)) {
d->movie->jumpToFrame(d->presetCurrentFrame);
d->presetCurrentFrame = 0;
}
- d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
+
+ QQuickPixmap *pixmap = d->infoForCurrentFrame(qmlEngine(this));
+ if (pixmap)
+ d->setPixmap(*pixmap);
if (isPlaying() != d->oldPlaying)
emit playingChanged();
@@ -512,7 +515,10 @@ void QQuickAnimatedImagePrivate::setMovie(QMovie *m)
Q_Q(QQuickAnimatedImage);
const int oldFrameCount = q->frameCount();
- delete movie;
+ if (movie) {
+ movie->disconnect();
+ movie->deleteLater();
+ }
movie = m;
if (oldFrameCount != q->frameCount())
diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
index 3e5a054cc7..8026bafb9e 100644
--- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
+++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
@@ -67,6 +67,7 @@ private slots:
void progressAndStatusChanges();
void playingAndPausedChanges();
void noCaching();
+ void sourceChangesOnFrameChanged();
};
void tst_qquickanimatedimage::cleanup()
@@ -590,6 +591,33 @@ void tst_qquickanimatedimage::noCaching()
}
}
+void tst_qquickanimatedimage::sourceChangesOnFrameChanged()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("colors.qml"));
+ QVector<QQuickAnimatedImage*> images;
+
+ // Run multiple animations in parallel, this should be fast
+ for (int loops = 0; loops < 25; ++loops) {
+ QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
+
+ // QTBUG-67427: this should not produce a segfault
+ QObject::connect(anim,
+ &QQuickAnimatedImage::frameChanged,
+ [this, anim]() { anim->setSource(testFileUrl("hearts.gif")); });
+
+ QVERIFY(anim);
+ QVERIFY(anim->isPlaying());
+
+ images.append(anim);
+ }
+
+ for (auto *anim : images)
+ QTRY_COMPARE(anim->source(), testFileUrl("hearts.gif"));
+
+ qDeleteAll(images);
+}
+
QTEST_MAIN(tst_qquickanimatedimage)
#include "tst_qquickanimatedimage.moc"