aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlpropertycache.cpp
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-03-23 14:16:43 +1000
committerQt by Nokia <qt-info@nokia.com>2012-08-27 05:17:13 +0200
commit965588737321d10fd1fbca3f89b4c6257b7b5d47 (patch)
tree95d069b6ce910c4f8bf8f71d50bebc4fe35a6b1f /src/qml/qml/qqmlpropertycache.cpp
parent4a161cfa0cf9167b575bdf7ff5685b9bf17c6960 (diff)
Restrict v8 property lookup to the execution context
When resolving property names, only properties known to the current context of execution should be available. If a property name has been overriden by a component extension, code executing in the context of the base component should resolve the property name to the property available inside the base component or its bases. Task-number: QTBUG-24891 Change-Id: I9687cc28e108226d5a939627a901c8254344b598 Reviewed-by: Michael Brasser <michael.brasser@nokia.com> Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/qml/qml/qqmlpropertycache.cpp')
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp240
1 files changed, 140 insertions, 100 deletions
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 3519d46017..9165f890c7 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -41,8 +41,9 @@
#include "qqmlpropertycache_p.h"
-#include "qqmlengine_p.h"
-#include "qqmlbinding_p.h"
+#include <private/qqmlengine_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlvmemetaobject_p.h>
#include <private/qv8engine_p.h>
#include <private/qmetaobject_p.h>
@@ -53,6 +54,7 @@
#include <QtCore/qdebug.h>
#include <ctype.h> // for toupper
+#include <limits.h>
#ifdef Q_CC_MSVC
// nonstandard extension used : zero-sized array in struct/union.
@@ -243,7 +245,8 @@ Creates a new empty QQmlPropertyCache.
*/
QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
+ signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+ _metaObject(0), argumentsCache(0)
{
Q_ASSERT(engine);
}
@@ -253,7 +256,8 @@ Creates a new QQmlPropertyCache of \a metaObject.
*/
QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
+ signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+ _metaObject(0), argumentsCache(0)
{
Q_ASSERT(engine);
Q_ASSERT(metaObject);
@@ -351,16 +355,14 @@ void QQmlPropertyCache::appendProperty(const QString &name,
data.notifyIndex = notifyIndex;
data.flags = flags;
- QHashedString string(name);
- if (QQmlPropertyData **old = stringCache.value(string)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int index = propertyIndexCache.count();
propertyIndexCache.append(data);
- stringCache.insert(string, propertyIndexCache.data() + propertyIndexCache.count() - 1);
+ setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
}
void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
@@ -372,15 +374,14 @@ void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
data.notifyIndex = notifyIndex;
data.flags = flags;
- if (QQmlPropertyData **old = stringCache.value(name)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int index = propertyIndexCache.count();
propertyIndexCache.append(data);
- stringCache.insert(name, propertyIndexCache.data() + propertyIndexCache.count() - 1);
+ setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
}
void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
@@ -410,21 +411,21 @@ void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int cor
data.arguments = args;
}
- QString handlerName = QLatin1String("on") + name;
- handlerName[2] = handlerName[2].toUpper();
-
- QHashedString string(name);
- if (QQmlPropertyData **old = stringCache.value(string)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int methodIndex = methodIndexCache.count();
methodIndexCache.append(data);
+
+ int signalHandlerIndex = signalHandlerIndexCache.count();
signalHandlerIndexCache.append(handler);
- stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
- stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
+ QString handlerName = QLatin1String("on") + name;
+ handlerName[2] = handlerName[2].toUpper();
+
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+ setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
}
void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
@@ -454,20 +455,21 @@ void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flag
data.arguments = args;
}
- QString handlerName = QLatin1String("on") + name.toUtf16();
- handlerName[2] = handlerName[2].toUpper();
-
- if (QQmlPropertyData **old = stringCache.value(name)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int methodIndex = methodIndexCache.count();
methodIndexCache.append(data);
+
+ int signalHandlerIndex = signalHandlerIndexCache.count();
signalHandlerIndexCache.append(handler);
- stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
- stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
+ QString handlerName = QLatin1String("on") + name.toUtf16();
+ handlerName[2] = handlerName[2].toUpper();
+
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+ setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
}
void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
@@ -497,16 +499,14 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor
data.flags = flags;
- QHashedString string(name);
- if (QQmlPropertyData **old = stringCache.value(string)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int methodIndex = methodIndexCache.count();
methodIndexCache.append(data);
- stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
}
void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
@@ -536,15 +536,14 @@ void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flag
data.flags = flags;
- if (QQmlPropertyData **old = stringCache.value(name)) {
- data.overrideIndexIsProperty = !(*old)->isFunction();
- data.overrideIndex = (*old)->coreIndex;
- (*old)->flags |= QQmlPropertyData::IsOverridden;
- }
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+ int methodIndex = methodIndexCache.count();
methodIndexCache.append(data);
- stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
}
// Returns this property cache's metaObject. May be null if it hasn't been created yet.
@@ -576,7 +575,7 @@ QString QQmlPropertyCache::defaultPropertyName() const
QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
- return property(defaultPropertyName());
+ return property(defaultPropertyName(), 0, 0);
}
QQmlPropertyCache *QQmlPropertyCache::parent() const
@@ -730,20 +729,20 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
if (utf8) {
QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
- if (QQmlPropertyData **it = stringCache.value(methodName))
- old = *it;
- stringCache.insert(methodName, data);
+ if (StringCache::mapped_type *it = stringCache.value(methodName))
+ old = it->second;
+ setNamedProperty(methodName, ii, data, (old != 0));
if (data->isSignal()) {
QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
- stringCache.insert(on, sigdata);
+ setNamedProperty(on, ii, sigdata, (old != 0));
++signalHandlerIndex;
}
} else {
QHashedCStringRef methodName(rawName, cptr - rawName);
- if (QQmlPropertyData **it = stringCache.value(methodName))
- old = *it;
- stringCache.insert(methodName, data);
+ if (StringCache::mapped_type *it = stringCache.value(methodName))
+ old = it->second;
+ setNamedProperty(methodName, ii, data, (old != 0));
if (data->isSignal()) {
int length = methodName.length();
@@ -757,7 +756,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
str[length + 2] = '\0';
QHashedString on(QString::fromLatin1(str.data()));
- stringCache.insert(on, sigdata);
+ setNamedProperty(on, ii, data, (old != 0));
++signalHandlerIndex;
}
}
@@ -766,9 +765,8 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
// We only overload methods in the same class, exactly like C++
if (old->isFunction() && old->coreIndex >= methodOffset)
data->flags |= QQmlPropertyData::IsOverload;
- data->overrideIndexIsProperty = !old->isFunction();
- data->overrideIndex = old->coreIndex;
- old->flags |= QQmlPropertyData::IsOverridden;
+
+ data->markAsOverrideOf(old);
}
}
@@ -806,14 +804,14 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
if (utf8) {
QHashedString propName(QString::fromUtf8(str, cptr - str));
- if (QQmlPropertyData **it = stringCache.value(propName))
- old = *it;
- stringCache.insert(propName, data);
+ if (StringCache::mapped_type *it = stringCache.value(propName))
+ old = it->second;
+ setNamedProperty(propName, ii, data, (old != 0));
} else {
QHashedCStringRef propName(str, cptr - str);
- if (QQmlPropertyData **it = stringCache.value(propName))
- old = *it;
- stringCache.insert(propName, data);
+ if (StringCache::mapped_type *it = stringCache.value(propName))
+ old = it->second;
+ setNamedProperty(propName, ii, data, (old != 0));
}
QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
@@ -826,13 +824,19 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
data->accessors = accessorProperty->accessors;
data->accessorData = accessorProperty->data;
} else if (old) {
- data->overrideIndexIsProperty = !old->isFunction();
- data->overrideIndex = old->coreIndex;
- old->flags |= QQmlPropertyData::IsOverridden;
+ data->markAsOverrideOf(old);
}
}
}
+QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
+{
+ if (p && p->notFullyResolved())
+ resolve(p);
+
+ return p;
+}
+
void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
{
Q_ASSERT(data->notFullyResolved());
@@ -918,8 +922,7 @@ QQmlPropertyCache::property(int index) const
return _parent->property(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
- if (rv->notFullyResolved()) resolve(rv);
- return rv;
+ return ensureResolved(rv);
}
QQmlPropertyData *
@@ -932,32 +935,60 @@ QQmlPropertyCache::method(int index) const
return _parent->method(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
- if (rv->notFullyResolved()) resolve(rv);
- return rv;
+ return ensureResolved(rv);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(const QHashedStringRef &str) const
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
{
- QQmlPropertyData **rv = stringCache.value(str);
- if (rv && (*rv)->notFullyResolved()) resolve(*rv);
- return rv?*rv:0;
+ QQmlData *data = (object ? QQmlData::get(object) : 0);
+ const QQmlVMEMetaObject *vmemo = (data && data->hasVMEMetaObject ? static_cast<const QQmlVMEMetaObject *>(object->metaObject()) : 0);
+ return findProperty(it, vmemo, context);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(const QHashedCStringRef &str) const
+namespace {
+
+inline bool contextHasNoExtensions(QQmlContextData *context)
{
- QQmlPropertyData **rv = stringCache.value(str);
- if (rv && (*rv)->notFullyResolved()) resolve(*rv);
- return rv?*rv:0;
+ // This context has no extension if its parent is the engine's rootContext,
+ // which has children but no imports
+ return (!context->parent || !context->parent->imports);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(const QString &str) const
+inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo)
{
- QQmlPropertyData **rv = stringCache.value(str);
- if (rv && (*rv)->notFullyResolved()) resolve(*rv);
- return rv?*rv:0;
+ return (prop->isFunction() ? vmemo->methodCount()
+ : prop->isSignalHandler() ? vmemo->signalCount()
+ : vmemo->propertyCount());
+}
+
+}
+
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const
+{
+ StringCache::ConstIterator end = stringCache.end();
+
+ if (it != end) {
+ if (vmemo && context && !contextHasNoExtensions(context)) {
+ // Find the highest property offset known to the supplied context
+ do {
+ if (vmemo->ctxt == context)
+ break;
+
+ vmemo = vmemo->parentVMEMetaObject();
+ } while (vmemo);
+ }
+
+ do {
+ // Is this property available to this context?
+ const StringCache::mapped_type &property(it.value());
+ if (!vmemo || (property.first < maximumIndexForProperty(property.second, vmemo)))
+ return ensureResolved(property.second);
+
+ it = stringCache.findNext(it);
+ } while (it != end);
+ }
+
+ return 0;
}
QString QQmlPropertyData::name(QObject *object)
@@ -983,6 +1014,14 @@ QString QQmlPropertyData::name(const QMetaObject *metaObject)
}
}
+void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
+{
+ overrideIndexIsProperty = !predecessor->isFunction();
+ overrideIndex = predecessor->coreIndex;
+
+ predecessor->flags |= QQmlPropertyData::IsOverridden;
+}
+
QStringList QQmlPropertyCache::propertyNames() const
{
QStringList keys;
@@ -1311,7 +1350,8 @@ inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
template<typename T>
QQmlPropertyData *
-qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local)
+qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name,
+ QQmlContextData *context, QQmlPropertyData &local)
{
QQmlPropertyCache *cache = 0;
@@ -1332,7 +1372,7 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlP
QQmlPropertyData *rv = 0;
if (cache) {
- rv = cache->property(name);
+ rv = cache->property(name, obj, context);
} else {
local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
if (local.isValid())
@@ -1343,17 +1383,17 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlP
}
QQmlPropertyData *
-QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
- const QHashedV8String &name, QQmlPropertyData &local)
+QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, const QHashedV8String &name,
+ QQmlContextData *context, QQmlPropertyData &local)
{
- return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
+ return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, context, local);
}
QQmlPropertyData *
QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
- const QString &name, QQmlPropertyData &local)
+ const QString &name, QQmlContextData *context, QQmlPropertyData &local)
{
- return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
+ return qQmlPropertyCacheProperty<QString>(engine, obj, name, context, local);
}
static inline const QMetaObjectPrivate *priv(const uint* data)
@@ -1416,7 +1456,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
QList<QPair<QString, QQmlPropertyData *> > methods;
for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
- Insert::in(this, properties, methods, iter, iter.value());
+ Insert::in(this, properties, methods, iter, iter.value().second);
Q_ASSERT(properties.count() == propertyIndexCache.count());
Q_ASSERT(methods.count() == methodIndexCache.count());
@@ -1477,7 +1517,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
}
if (!_defaultPropertyName.isEmpty()) {
- QQmlPropertyData *dp = property(_defaultPropertyName);
+ QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0);
if (dp && dp->coreIndex >= propertyIndexCacheStart) {
Q_ASSERT(!dp->isFunction());
builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());