aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/v8
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/v8
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/v8')
-rw-r--r--src/qml/qml/v8/qv8contextwrapper.cpp8
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp57
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper_p.h20
-rw-r--r--src/qml/qml/v8/qv8typewrapper.cpp12
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper.cpp7
5 files changed, 57 insertions, 47 deletions
diff --git a/src/qml/qml/v8/qv8contextwrapper.cpp b/src/qml/qml/v8/qv8contextwrapper.cpp
index 82ff64fac5..80d4000d31 100644
--- a/src/qml/qml/v8/qv8contextwrapper.cpp
+++ b/src/qml/qml/v8/qv8contextwrapper.cpp
@@ -323,7 +323,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
// Search scope object
if (scopeObject) {
v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, propertystring,
- QV8QObjectWrapper::CheckRevision);
+ context, QV8QObjectWrapper::CheckRevision);
if (!result.IsEmpty()) return result;
}
scopeObject = 0;
@@ -332,7 +332,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
// Search context object
if (context->contextObject) {
v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, propertystring,
- QV8QObjectWrapper::CheckRevision);
+ context, QV8QObjectWrapper::CheckRevision);
if (!result.IsEmpty()) return result;
}
@@ -396,13 +396,13 @@ v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property,
// Search scope object
if (scopeObject &&
- qobjectWrapper->setProperty(scopeObject, propertystring, value, QV8QObjectWrapper::CheckRevision))
+ qobjectWrapper->setProperty(scopeObject, propertystring, context, value, QV8QObjectWrapper::CheckRevision))
return value;
scopeObject = 0;
// Search context object
if (context->contextObject &&
- qobjectWrapper->setProperty(context->contextObject, propertystring, value,
+ qobjectWrapper->setProperty(context->contextObject, propertystring, context, value,
QV8QObjectWrapper::CheckRevision))
return value;
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index 627e453a77..9cb3410478 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -479,6 +479,7 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject *object,
v8::Handle<v8::Value> *objectHandle,
const QHashedV8String &property,
+ QQmlContextData *context,
QV8QObjectWrapper::RevisionMode revisionMode)
{
// XXX More recent versions of V8 introduced "Callable" objects. It is possible that these
@@ -525,9 +526,9 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
{
QQmlData *ddata = QQmlData::get(object, false);
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(property);
+ result = ddata->propertyCache->property(property, object, context);
else
- result = QQmlPropertyCache::property(engine->engine(), object, property, local);
+ result = QQmlPropertyCache::property(engine->engine(), object, property, context, local);
}
if (!result)
@@ -708,7 +709,7 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
}
}
-bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QHashedV8String &property,
+bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QHashedV8String &property, QQmlContextData *context,
v8::Handle<v8::Value> value, QV8QObjectWrapper::RevisionMode revisionMode)
{
if (engine->qobjectWrapper()->m_toStringString == property ||
@@ -720,7 +721,7 @@ bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QH
QQmlPropertyData local;
QQmlPropertyData *result = 0;
- result = QQmlPropertyCache::property(engine->engine(), object, property, local);
+ result = QQmlPropertyCache::property(engine->engine(), object, property, context, local);
if (!result)
return false;
@@ -756,16 +757,16 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property,
QHashedV8String propertystring(property);
QV8Engine *v8engine = resource->engine;
+ QQmlContextData *context = v8engine->callingContext();
+
v8::Handle<v8::Value> This = info.This();
v8::Handle<v8::Value> result = GetProperty(v8engine, object, &This, propertystring,
- QV8QObjectWrapper::IgnoreRevision);
+ context, QV8QObjectWrapper::IgnoreRevision);
if (!result.IsEmpty())
return result;
if (QV8Engine::startsWithUpper(property)) {
// Check for attached properties
- QQmlContextData *context = v8engine->callingContext();
-
if (context && context->imports) {
QQmlTypeNameCache::Result r = context->imports->query(propertystring);
@@ -800,7 +801,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
QHashedV8String propertystring(property);
QV8Engine *v8engine = resource->engine;
- bool result = SetProperty(v8engine, object, propertystring, value, QV8QObjectWrapper::IgnoreRevision);
+ QQmlContextData *context = v8engine->callingContext();
+ bool result = SetProperty(v8engine, object, propertystring, context, value, QV8QObjectWrapper::IgnoreRevision);
if (!result) {
QString error = QLatin1String("Cannot assign to non-existent property \"") +
@@ -822,12 +824,13 @@ v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
QV8Engine *engine = resource->engine;
QObject *object = resource->object;
+ QQmlContextData *context = engine->callingContext();
QHashedV8String propertystring(property);
QQmlPropertyData local;
QQmlPropertyData *result = 0;
- result = QQmlPropertyCache::property(engine->engine(), object, propertystring, local);
+ result = QQmlPropertyCache::property(engine->engine(), object, propertystring, context, local);
if (!result)
return v8::Handle<v8::Integer>();
@@ -960,35 +963,37 @@ v8::Local<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *
if (constructor.IsEmpty()) {
v8::Local<v8::FunctionTemplate> ft;
- QString toString = QLatin1String("toString");
- QString destroy = QLatin1String("destroy");
+ const QHashedString toString(QStringLiteral("toString"));
+ const QHashedString destroy(QStringLiteral("destroy"));
+
+ // As we use hash linking, or with property overrides, it is possible that iterating
+ // over the values can yield duplicates. To combat this, we must unique'ify our properties.
+ const bool checkForDuplicates = stringCache.isLinked() || _hasPropertyOverrides;
- // As we use hash linking, it is possible that iterating over the values can give duplicates.
- // To combat this, we must unique'ify our properties.
StringCache uniqueHash;
- if (stringCache.isLinked())
+ if (checkForDuplicates)
uniqueHash.reserve(stringCache.count());
// XXX TODO: Enables fast property accessors. These more than double the property access
// performance, but the cost of setting up this structure hasn't been measured so
// its not guarenteed that this is a win overall. We need to try and measure the cost.
for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) {
- if (stringCache.isLinked()) {
+ if (iter.equals(toString) || iter.equals(destroy))
+ continue;
+
+ if (checkForDuplicates) {
if (uniqueHash.contains(iter))
continue;
uniqueHash.insert(iter);
}
- QQmlPropertyData *property = *iter;
+ QQmlPropertyData *property = (*iter).second;
if (property->notFullyResolved()) resolve(property);
if (property->isFunction())
continue;
v8::AccessorGetter fastgetter = 0;
- v8::AccessorSetter fastsetter = FastValueSetter;
- if (!property->isWritable())
- fastsetter = FastValueSetterReadOnly;
if (property->isQObject())
fastgetter = FAST_GETTER_FUNCTION(property, QObject*);
@@ -1006,10 +1011,6 @@ v8::Local<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *
fastgetter = FAST_GETTER_FUNCTION(property, double);
if (fastgetter) {
- QString name = iter.key();
- if (name == toString || name == destroy)
- continue;
-
if (ft.IsEmpty()) {
ft = v8::FunctionTemplate::New();
ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
@@ -1020,11 +1021,15 @@ v8::Local<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *
ft->InstanceTemplate()->SetHasExternalResource(true);
}
+ v8::AccessorSetter fastsetter = FastValueSetter;
+ if (!property->isWritable())
+ fastsetter = FastValueSetterReadOnly;
+
// We wrap the raw QQmlPropertyData pointer here. This is safe as the
// pointer will remain valid at least as long as the lifetime of any QObject's of
// this type and the property accessor checks if the object is 0 (deleted) before
// dereferencing the pointer.
- ft->InstanceTemplate()->SetAccessor(engine->toString(name), fastgetter, fastsetter,
+ ft->InstanceTemplate()->SetAccessor(engine->toString(iter.key()), fastgetter, fastsetter,
v8::External::Wrap(property));
}
}
@@ -1371,13 +1376,13 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Connect(const v8::Arguments &args)
QObject *signalObject = signalInfo.first;
int signalIndex = signalInfo.second;
- if (signalIndex == -1)
+ if (signalIndex < 0)
V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
if (!signalObject)
V8THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
- if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
v8::Local<v8::Value> functionValue;
diff --git a/src/qml/qml/v8/qv8qobjectwrapper_p.h b/src/qml/qml/v8/qv8qobjectwrapper_p.h
index de2ec30e44..88d36342cc 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper_p.h
+++ b/src/qml/qml/v8/qv8qobjectwrapper_p.h
@@ -100,8 +100,8 @@ public:
static QObject *toQObject(QV8ObjectResource *);
enum RevisionMode { IgnoreRevision, CheckRevision };
- inline v8::Handle<v8::Value> getProperty(QObject *, const QHashedV8String &, RevisionMode);
- inline bool setProperty(QObject *, const QHashedV8String &, v8::Handle<v8::Value>, RevisionMode);
+ inline v8::Handle<v8::Value> getProperty(QObject *, const QHashedV8String &, QQmlContextData *, RevisionMode);
+ inline bool setProperty(QObject *, const QHashedV8String &, QQmlContextData *, v8::Handle<v8::Value>, RevisionMode);
void registerWeakQObjectReference(QV8QObjectResource *resource)
{
@@ -121,8 +121,8 @@ private:
v8::Local<v8::Object> newQObject(QObject *, QQmlData *, QV8Engine *);
bool deleteWeakQObject(QV8QObjectResource *resource, bool calledFromEngineDtor = false);
static v8::Handle<v8::Value> GetProperty(QV8Engine *, QObject *, v8::Handle<v8::Value> *,
- const QHashedV8String &, QV8QObjectWrapper::RevisionMode);
- static bool SetProperty(QV8Engine *, QObject *, const QHashedV8String &,
+ const QHashedV8String &, QQmlContextData *, QV8QObjectWrapper::RevisionMode);
+ static bool SetProperty(QV8Engine *, QObject *, const QHashedV8String &, QQmlContextData *,
v8::Handle<v8::Value>, QV8QObjectWrapper::RevisionMode);
static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
const v8::AccessorInfo &info);
@@ -156,24 +156,24 @@ private:
};
v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &string,
- RevisionMode mode)
+ QQmlContextData *context, RevisionMode mode)
{
QQmlData *dd = QQmlData::get(object, false);
if (!dd || !dd->propertyCache || m_toStringString == string || m_destroyString == string ||
- dd->propertyCache->property(string)) {
- return GetProperty(m_engine, object, 0, string, mode);
+ dd->propertyCache->property(string, object, context)) {
+ return GetProperty(m_engine, object, 0, string, context, mode);
} else {
return v8::Handle<v8::Value>();
}
}
bool QV8QObjectWrapper::setProperty(QObject *object, const QHashedV8String &string,
- v8::Handle<v8::Value> value, RevisionMode mode)
+ QQmlContextData *context, v8::Handle<v8::Value> value, RevisionMode mode)
{
QQmlData *dd = QQmlData::get(object, false);
if (!dd || !dd->propertyCache || m_toStringString == string || m_destroyString == string ||
- dd->propertyCache->property(string)) {
- return SetProperty(m_engine, object, string, value, mode);
+ dd->propertyCache->property(string, object, context)) {
+ return SetProperty(m_engine, object, string, context, value, mode);
} else {
return false;
}
diff --git a/src/qml/qml/v8/qv8typewrapper.cpp b/src/qml/qml/v8/qv8typewrapper.cpp
index 4400d30abf..25695a9fbc 100644
--- a/src/qml/qml/v8/qv8typewrapper.cpp
+++ b/src/qml/qml/v8/qv8typewrapper.cpp
@@ -165,6 +165,8 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
return v8::Undefined();
QV8Engine *v8engine = resource->engine;
+ QQmlContextData *context = v8engine->callingContext();
+
QObject *object = resource->object;
QHashedV8String propertystring(property);
@@ -183,7 +185,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
} else if (resource->object) {
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- return v8engine->qobjectWrapper()->getProperty(ao, propertystring,
+ return v8engine->qobjectWrapper()->getProperty(ao, propertystring, context,
QV8QObjectWrapper::IgnoreRevision);
// Fall through to return empty handle
@@ -241,7 +243,8 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
}
// check for property.
- v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(singletonType->qobjectApi, propertystring, QV8QObjectWrapper::IgnoreRevision);
+ v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(singletonType->qobjectApi, propertystring,
+ context, QV8QObjectWrapper::IgnoreRevision);
return rv;
} else if (!singletonType->scriptApi.isUndefined()) {
// NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
@@ -272,6 +275,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
return value;
QV8Engine *v8engine = resource->engine;
+ QQmlContextData *context = v8engine->callingContext();
QHashedV8String propertystring(property);
@@ -280,7 +284,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
QObject *object = resource->object;
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- v8engine->qobjectWrapper()->setProperty(ao, propertystring, value,
+ v8engine->qobjectWrapper()->setProperty(ao, propertystring, context, value,
QV8QObjectWrapper::IgnoreRevision);
} else if (resource->typeNamespace) {
if (QQmlMetaType::SingletonInstance *singletonType = resource->typeNamespace->singletonType(resource->importNamespace)) {
@@ -295,7 +299,7 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
}
if (singletonType->qobjectApi) {
- v8engine->qobjectWrapper()->setProperty(singletonType->qobjectApi, propertystring, value,
+ v8engine->qobjectWrapper()->setProperty(singletonType->qobjectApi, propertystring, context, value,
QV8QObjectWrapper::IgnoreRevision);
} else if (!singletonType->scriptApi.isUndefined()) {
QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp
index 0408df4b00..33166322ed 100644
--- a/src/qml/qml/v8/qv8valuetypewrapper.cpp
+++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp
@@ -313,10 +313,10 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property
{
QQmlData *ddata = QQmlData::get(r->type, false);
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(propertystring);
+ result = ddata->propertyCache->property(propertystring, 0, 0);
else
result = QQmlPropertyCache::property(r->engine->engine(), r->type,
- propertystring, local);
+ propertystring, 0, local);
}
if (!result)
@@ -324,7 +324,8 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property
if (result->isFunction()) {
// calling a Q_INVOKABLE function of a value type
- return r->engine->qobjectWrapper()->getProperty(r->type, propertystring, QV8QObjectWrapper::IgnoreRevision);
+ QQmlContextData *context = r->engine->callingContext();
+ return r->engine->qobjectWrapper()->getProperty(r->type, propertystring, context, QV8QObjectWrapper::IgnoreRevision);
}
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \