diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-12-07 23:18:48 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-12-10 17:18:14 +0100 |
commit | 8d848811dca437c125b45bdf03fb307ce9ca512f (patch) | |
tree | 4c0c822eb28bdb6ab274ebdd3e05a5b502abb7f1 | |
parent | e06fbc85ddacc193b16dc8eee1007f7e7d5d3c80 (diff) |
V4 Lookup: Do not leak property caches
When a function that performs a lookup is called recursively via the
flushing of initial bindings, we may initialize the same lookup twice.
In that case, make sure to release the old property cache before
overwriting it.
We might suspect that this can only re-assign the same property cache
again and therefore we can skip the whole operation if it has been done
before. Yet, considering the dynamic nature of QML, it's very hard to
guarantee this. There are cases where we have to revert lookups because
the types don't match anymore at the time we call them again. I cannot
rule out the possibility of this happening during initialization.
Therefore, the code doesn't try to be clever about this case and instead
just blindly overwrites the lookup (like it did before, just without
leaking).
Fixes: QTBUG-98722
Change-Id: I536deef282bbff723f79a82e4d9e694c3d2d32df
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 90790ef23bb148b4ac4c055bd3c11153b4c9a502)
-rw-r--r-- | src/qml/jsruntime/qv4lookup_p.h | 29 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qmlcontext.cpp | 13 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper.cpp | 7 |
4 files changed, 35 insertions, 19 deletions
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 9b8e0def4a..deb23d8c58 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -223,6 +223,35 @@ Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value); // across 32-bit and 64-bit (matters when cross-compiling). Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0); +inline void setupQObjectLookup( + Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData) +{ + if (QQmlPropertyCache *cache = lookup->qobjectLookup.propertyCache) + cache->release(); + + Q_ASSERT(ddata->propertyCache != nullptr); + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = propertyData; +} + +inline void setupQObjectLookup( + Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData, + const Object *self) +{ + lookup->qobjectLookup.ic = self->internalClass(); + setupQObjectLookup(lookup, ddata, propertyData); +} + + +inline void setupQObjectLookup( + Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData, + const Object *self, const Object *qmlType) +{ + lookup->qobjectLookup.qmlTypeIc = qmlType->internalClass(); + setupQObjectLookup(lookup, ddata, propertyData, self); +} + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index cc06625827..314a9e1356 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -294,11 +294,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r QQmlData *ddata = QQmlData::get(scopeObject, false); if (ddata && ddata->propertyCache) { ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject))); - const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); - lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = propertyData; + QV4::setupQObjectLookup(lookup, ddata, propertyData, val->objectValue()); lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScopeObjectProperty; } } @@ -326,11 +322,8 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r QQmlData *ddata = QQmlData::get(context->contextObject, false); if (ddata && ddata->propertyCache) { ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); - const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); - lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = propertyData; + QV4::setupQObjectLookup(lookup, ddata, propertyData, + val->objectValue()); lookup->qmlContextPropertyGetter = contextGetterFunction; } } else if (originalLookup) { diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 659529e502..91d7712be0 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -875,10 +875,7 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E return QV4::Object::virtualResolveLookupGetter(object, engine, lookup); } - lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = property; + QV4::setupQObjectLookup(lookup, ddata, property, This); lookup->getter = QV4::QObjectWrapper::lookupGetter; return lookup->getter(lookup, engine, *object); } diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 1d88a40485..6bf9455e17 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -458,11 +458,8 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); if (property) { ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); - lookup->qobjectLookup.qmlTypeIc = This->internalClass(); - lookup->qobjectLookup.ic = val->objectValue()->internalClass(); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = property; + setupQObjectLookup(lookup, ddata, property, + val->objectValue(), This); lookup->getter = QQmlTypeWrapper::lookupSingletonProperty; return lookup->getter(lookup, engine, *object); } |