aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-12-07 23:18:48 +0100
committerUlf Hermann <ulf.hermann@qt.io>2021-12-10 17:18:14 +0100
commit8d848811dca437c125b45bdf03fb307ce9ca512f (patch)
tree4c0c822eb28bdb6ab274ebdd3e05a5b502abb7f1
parente06fbc85ddacc193b16dc8eee1007f7e7d5d3c80 (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.h29
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp13
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp5
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp7
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);
}