aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-06-11 10:14:15 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-06-12 08:56:29 +0000
commit7625d207587c52a3686453ce615187cf6ab90996 (patch)
tree9f2a6aabd47ecdfee1a9977d9f51fb672b344479
parent44e5f7f29c29811534ca02359fe5b4fbe1f54990 (diff)
Handle objects without QQmlData and objects being deleted in AOT lookups
Otherwise we trigger asserts in various places. We also need to generate exceptions matching those the interpreter generates, and we need to decline capturing of nullptr objects. Change-Id: I65744fa3e440939db28d7b16a044f6968500a67b Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 603ea30924ea925db2830efa2b2c5cef500ee528) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/qml/qml/qqml.cpp97
1 files changed, 81 insertions, 16 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 70525f98a4..f5cdb910d7 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -737,28 +737,40 @@ static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCach
return false;
}
-static bool loadObjectProperty(QV4::Lookup *l, QObject *object, void *target,
+enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
+
+static ObjectPropertyResult loadObjectProperty(QV4::Lookup *l, QObject *object, void *target,
QQmlContextData *qmlContext)
{
+ const QQmlData *qmlData = QQmlData::get(object);
+ if (!qmlData)
+ return ObjectPropertyResult::NeedsInit;
+ if (qmlData->isQueuedForDeletion)
+ return ObjectPropertyResult::Deleted;
Q_ASSERT(!QQmlData::wasDeleted(object));
const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
- if (!inherits(QQmlData::get(object)->propertyCache, propertyCache))
- return false;
+ if (!inherits(qmlData->propertyCache, propertyCache))
+ return ObjectPropertyResult::NeedsInit;
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
captureObjectProperty(object, propertyCache, property, qmlContext);
property->readProperty(object, target);
- return true;
+ return ObjectPropertyResult::OK;
}
-static bool storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
+static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
{
+ const QQmlData *qmlData = QQmlData::get(object);
+ if (!qmlData)
+ return ObjectPropertyResult::NeedsInit;
+ if (qmlData->isQueuedForDeletion)
+ return ObjectPropertyResult::Deleted;
Q_ASSERT(!QQmlData::wasDeleted(object));
- if (!inherits(QQmlData::get(object)->propertyCache, l->qobjectLookup.propertyCache))
- return false;
+ if (!inherits(qmlData->propertyCache, l->qobjectLookup.propertyCache))
+ return ObjectPropertyResult::NeedsInit;
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
property->writeProperty(object, value, {});
- return true;
+ return ObjectPropertyResult::OK;
}
static bool initObjectLookup(
@@ -777,6 +789,8 @@ static bool initObjectLookup(
QQmlData *ddata = QQmlData::get(object, true);
Q_ASSERT(ddata);
+ if (ddata->isQueuedForDeletion)
+ return false;
QQmlPropertyData *property;
if (!ddata->propertyCache) {
@@ -862,6 +876,9 @@ static void amendException(QV4::ExecutionEngine *engine)
bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
{
+ if (!object)
+ return false;
+
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
if (l->getter != QV4::QQmlTypeWrapper::lookupSingletonProperty
&& l->getter != QV4::QObjectWrapper::lookupGetter) {
@@ -917,8 +934,17 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
l.clear();
l.nameIndex = nameIndex;
if (initObjectLookup(this, &l, qmlScopeObject, type)) {
- if (!storeObjectProperty(&l, qmlScopeObject, value))
+ switch (storeObjectProperty(&l, qmlScopeObject, value)) {
+ case ObjectPropertyResult::NeedsInit:
engine->handle()->throwTypeError();
+ break;
+ case ObjectPropertyResult::Deleted:
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ break;
+ case ObjectPropertyResult::OK:
+ break;
+ }
l.qobjectLookup.propertyCache->release();
} else {
engine->handle()->throwTypeError();
@@ -1081,7 +1107,19 @@ bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target)
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupScopeObjectProperty)
return false;
- return loadObjectProperty(l, qmlScopeObject, target, qmlContext);
+
+ switch (loadObjectProperty(l, qmlScopeObject, target, qmlContext)) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted:
+ Q_UNREACHABLE(); // The scope object should really stay alive
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE();
+ return false;
}
void AOTCompiledContext::initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const
@@ -1173,18 +1211,32 @@ void AOTCompiledContext::initLoadAttachedLookup(uint index, QObject *object) con
bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *target) const
{
+
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (!object) {
+ const auto doThrow = [&]() {
engine->handle()->throwTypeError(
QStringLiteral("Cannot read property '%1' of null")
.arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
return false;
- }
+ };
+
+ if (!object)
+ return doThrow();
if (l->getter != QV4::QObjectWrapper::lookupGetter)
return false;
- return loadObjectProperty(l, object, target, qmlContext);
+ switch (loadObjectProperty(l, object, target, qmlContext)) {
+ case ObjectPropertyResult::Deleted:
+ return doThrow();
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE();
+ return false;
}
void AOTCompiledContext::initGetObjectLookup(uint index, QObject *object, QMetaType type) const
@@ -1255,17 +1307,30 @@ void AOTCompiledContext::initGetEnumLookup(
bool AOTCompiledContext::setObjectLookup(uint index, QObject *object, void *value) const
{
- if (!object) {
+ const auto doThrow = [&]() {
engine->handle()->throwTypeError(
QStringLiteral("Value is null and could not be converted to an object"));
return false;
- }
+ };
+
+ if (!object)
+ return doThrow();
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
if (l->setter != QV4::QObjectWrapper::lookupSetter)
return false;
- return storeObjectProperty(l, object, value);
+ switch (storeObjectProperty(l, object, value)) {
+ case ObjectPropertyResult::Deleted:
+ return doThrow();
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE();
+ return false;
}
void AOTCompiledContext::initSetObjectLookup(uint index, QObject *object, QMetaType type) const