diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-14 12:37:40 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-23 16:15:00 +0200 |
commit | 48b707224efaa54b4dfd831cfd8fbe9006f99588 (patch) | |
tree | 7cdefb068ef609ba1252d5bca0e5f4aabc5f7bfe | |
parent | cf7d990a486b406d558e3291247d4323a9f48c73 (diff) |
Fix invalid vptr during destruction of animations
Fixes UBSAN warnings about objects used after partial destruction.
Change-Id: Iceea083a77d47335ef595c0ff97b87f35f42e56f
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/corelib/animation/qabstractanimation.cpp | 2 | ||||
-rw-r--r-- | src/corelib/animation/qanimationgroup.cpp | 25 | ||||
-rw-r--r-- | src/corelib/animation/qanimationgroup_p.h | 2 | ||||
-rw-r--r-- | src/corelib/animation/qsequentialanimationgroup.cpp | 3 |
4 files changed, 30 insertions, 2 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index b507049cc4..8a9d86b7c5 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -1067,6 +1067,8 @@ QAbstractAnimation::~QAbstractAnimation() if (oldState == QAbstractAnimation::Running) QAnimationTimer::unregisterAnimation(this); } + if (d->group) + d->group->removeAnimation(this); } /*! diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp index f47d99eb68..ed40817222 100644 --- a/src/corelib/animation/qanimationgroup.cpp +++ b/src/corelib/animation/qanimationgroup.cpp @@ -113,6 +113,11 @@ QAnimationGroup::QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent) */ QAnimationGroup::~QAnimationGroup() { + Q_D(QAnimationGroup); + // We need to clear the animations now while we are still a valid QAnimationGroup. + // If we wait until ~QObject() the QAbstractAnimation's pointer back to us would + // point to a QObject, not a valid QAnimationGroup. + d->clear(true); } /*! @@ -256,7 +261,7 @@ QAbstractAnimation *QAnimationGroup::takeAnimation(int index) void QAnimationGroup::clear() { Q_D(QAnimationGroup); - qDeleteAll(d->animations); + d->clear(false); } /*! @@ -284,6 +289,24 @@ bool QAnimationGroup::event(QEvent *event) return QAbstractAnimation::event(event); } +void QAnimationGroupPrivate::clear(bool onDestruction) +{ + const QList<QAbstractAnimation *> animationsCopy = animations; // taking a copy + animations.clear(); + // Clearing backwards so the indices doesn't change while we remove animations. + for (int i = animationsCopy.count() - 1; i >= 0; --i) { + QAbstractAnimation *animation = animationsCopy.at(i); + animation->setParent(nullptr); + QAbstractAnimationPrivate::get(animation)->group = nullptr; + // If we are in ~QAnimationGroup() it is not safe to called the virtual + // animationRemoved method, which can still be a method in a + // QAnimationGroupPrivate derived class that assumes q_ptr is still + // a valid derived class of QAnimationGroup. + if (!onDestruction) + animationRemoved(i, animation); + delete animation; + } +} void QAnimationGroupPrivate::animationRemoved(int index, QAbstractAnimation *) { diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h index ff759d11fd..d0b2e9f9bb 100644 --- a/src/corelib/animation/qanimationgroup_p.h +++ b/src/corelib/animation/qanimationgroup_p.h @@ -73,6 +73,8 @@ public: virtual void animationInsertedAt(int) { } virtual void animationRemoved(int, QAbstractAnimation *); + void clear(bool onDestruction); + void disconnectUncontrolledAnimation(QAbstractAnimation *anim) { //0 for the signal here because we might be called from the animation destructor diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp index 150e74d7d6..66e346a2fe 100644 --- a/src/corelib/animation/qsequentialanimationgroup.cpp +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -532,7 +532,8 @@ void QSequentialAnimationGroupPrivate::animationRemoved(int index, QAbstractAnim Q_Q(QSequentialAnimationGroup); QAnimationGroupPrivate::animationRemoved(index, anim); - Q_ASSERT(currentAnimation); // currentAnimation should always be set + if (!currentAnimation) + return; if (actualDuration.size() > index) actualDuration.removeAt(index); |