diff options
| author | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-03-13 14:53:39 +0100 |
|---|---|---|
| committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-06-13 20:35:32 +0200 |
| commit | 8a74155411d7a22bb8efa405fe59a681e47e6b45 (patch) | |
| tree | 50c26f7191fb511bdb148d7d56538f5000579114 /src/quick/util/qquickanimation.cpp | |
| parent | aea823b493d0779c1019b27fc8a2203fe162f235 (diff) | |
PropertyAnimation: Handle targets being deleted
QQuickPropertyAnimation does not own the targets in its targets list.
Thus, we need to be careful to not access deleted objects. Calling
QQmlData::wasDeleted is not enoguh, as the object might be fully
deleted, but we'd still have a dangling pointer to it.
Fix the issue by using QPointer. A similar issue might exists for
target, but there we don't normally end up with dangling references -
the engine will correctly null the target. And the QPointer isNull
check will avoid potentiall nullptr derefences there, too.
Ideally, we would use QQmlGuard instead of QPointer, as it would have a
lower overhead - however, we run into linker issues on MSVC. Fixing them
is deferred to a future commit, to not block this crash fix.
Fixes: QTBUG-100392
Pick-to: 6.5 6.6 6.2
Change-Id: If084e2e0f22d50dbee8bf5aedfa2e749e79fc105
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src/quick/util/qquickanimation.cpp')
| -rw-r--r-- | src/quick/util/qquickanimation.cpp | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp index 113fcf50f0..5aa2eaa1f4 100644 --- a/src/quick/util/qquickanimation.cpp +++ b/src/quick/util/qquickanimation.cpp @@ -2649,7 +2649,38 @@ void QQuickPropertyAnimation::setProperties(const QString &prop) QQmlListProperty<QObject> QQuickPropertyAnimation::targets() { Q_D(QQuickPropertyAnimation); - return QQmlListProperty<QObject>(this, &(d->targets)); + using ListPtr = QList<QPointer<QObject>> *; + using LP = QQmlListProperty<QObject>; + LP::AppendFunction appendFn = [](LP *prop, QObject *value) + { + static_cast<ListPtr>(prop->data)->append(value); + }; + LP::CountFunction countFn = [](LP *prop) + { + return static_cast<ListPtr>(prop->data)->size(); + }; + + LP::AtFunction atFn = [](LP *prop, qsizetype index) -> QObject * + { + return static_cast<ListPtr>(prop->data)->at(index); + }; + + LP::ClearFunction clearFN = [](LP *prop) + { + return static_cast<ListPtr>(prop->data)->clear(); + }; + + LP::ReplaceFunction replaceFn = [](LP *prop, qsizetype index, QObject *value) + { + static_cast<ListPtr>(prop->data)->replace(index, value); + }; + + LP::RemoveLastFunction removeLastFn = [](LP *prop) + { + static_cast<ListPtr>(prop->data)->removeLast(); + }; + + return QQmlListProperty<QObject>(this, &(d->targets), appendFn, countFn, atFn, clearFN, replaceFn, removeLastFn); } /*! @@ -2721,7 +2752,7 @@ QQuickStateActions QQuickPropertyAnimation::createTransitionActions(QQuickStateA if (!d->propertyName.isEmpty()) props << d->propertyName; - QList<QObject*> targets = d->targets; + QList<QPointer<QObject>> targets = d->targets; if (d->target) targets.append(d->target); @@ -2750,10 +2781,14 @@ QQuickStateActions QQuickPropertyAnimation::createTransitionActions(QQuickStateA for (int i = 0; i < props.size(); ++i) { for (int j = 0; j < targets.size(); ++j) { + const auto& guarded = targets.at(j); + if (guarded.isNull()) + continue; + QObject *target = guarded.get(); QQuickStateAction myAction; QString errorMessage; const QString &propertyName = props.at(i); - myAction.property = d->createProperty(targets.at(j), propertyName, this, &errorMessage); + myAction.property = d->createProperty(target, propertyName, this, &errorMessage); if (myAction.property.isValid()) { if (usingDefaultProperties) successfullyCreatedDefaultProperty = true; |
