diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-06-07 13:21:09 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-06-26 20:42:39 +0200 |
commit | a3389d6bf238c46816fd1133c1258102e36c4b10 (patch) | |
tree | ddbaabaa2129a9e8f425aded7706ebb91e36c2c5 /src | |
parent | 9240878b2e770dc81d22c51e95a3f6fd2e23acef (diff) |
QML: Do not leak memory if QQmlData is manipulated from ctor
This creates another QQmlData object on the heap, which is rather
wasteful. However, we cannot really avoid it since it's all too easy to
trigger an operation like this.
If it happens, use the QQmlData it has created, and ignore the memory
we've allocated inline. While we're at it, make the memory ownership a
required argument to the ctor.
Pick-to: 6.5 6.6
Fixes: QTBUG-114186
Change-Id: I0568768c9ec13c94db79bb162c9eeb76f75f2a55
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/qml/qqmldata_p.h | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmltype.cpp | 5 | ||||
-rw-r--r-- | src/qmlmodels/qqmllistmodel.cpp | 9 |
4 files changed, 15 insertions, 11 deletions
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 5b7c05c61e..cc13cc7245 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -55,7 +55,9 @@ struct Binding; class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData { public: - QQmlData(); + enum Ownership { DoesNotOwnMemory, OwnsMemory }; + + QQmlData(Ownership ownership); ~QQmlData(); static inline void init() { @@ -295,7 +297,7 @@ private: Q_NEVER_INLINE BindingBitsType *growBits(QObject *obj, int bit); - Q_DISABLE_COPY(QQmlData); + Q_DISABLE_COPY_MOVE(QQmlData); }; bool QQmlData::wasDeleted(const QObjectPrivate *priv) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index c9b0912706..a8a185772b 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -255,8 +255,8 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) } } -QQmlData::QQmlData() - : ownMemory(true), indestructible(true), explicitIndestructibleSet(false), +QQmlData::QQmlData(Ownership ownership) + : ownMemory(ownership == OwnsMemory), indestructible(true), explicitIndestructibleSet(false), hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), hasInterceptorMetaObject(false), hasVMEMetaObject(false), hasConstWrapper(false), bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr), @@ -1525,7 +1525,7 @@ QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv) { Q_ASSERT(priv); Q_ASSERT(!priv->isDeletingChildren); - priv->declarativeData = new QQmlData; + priv->declarativeData = new QQmlData(OwnsMemory); return static_cast<QQmlData *>(priv->declarativeData); } diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index 56f19f877a..ece6454705 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -491,11 +491,10 @@ QObject *QQmlType::createWithQQmlData() const auto instance = create(&ddataMemory, sizeof(QQmlData)); if (!instance) return nullptr; - QQmlData *ddata = new (ddataMemory) QQmlData; - ddata->ownMemory = false; QObjectPrivate* p = QObjectPrivate::get(instance); Q_ASSERT(!p->isDeletingChildren); - p->declarativeData = ddata; + if (!p->declarativeData) + p->declarativeData = new (ddataMemory) QQmlData(QQmlData::DoesNotOwnMemory); return instance; } diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp index 14c8a6fd85..3bd180d072 100644 --- a/src/qmlmodels/qqmllistmodel.cpp +++ b/src/qmlmodels/qqmllistmodel.cpp @@ -319,9 +319,12 @@ QObject *ListModel::getOrCreateModelObject(QQmlListModel *model, int elementInde void *memory = operator new(sizeof(QObject) + sizeof(QQmlData)); void *ddataMemory = ((char *)memory) + sizeof(QObject); e->m_objectCache = new (memory) QObject; - QQmlData *ddata = new (ddataMemory) QQmlData; - ddata->ownMemory = false; - QObjectPrivate::get(e->m_objectCache)->declarativeData = ddata; + + const QAbstractDeclarativeData *old = std::exchange( + QObjectPrivate::get(e->m_objectCache)->declarativeData, + new (ddataMemory) QQmlData(QQmlData::DoesNotOwnMemory)); + Q_ASSERT(!old); // QObject should really not manipulate QQmlData + (void)new ModelNodeMetaObject(e->m_objectCache, model, elementIndex); } return e->m_objectCache; |