diff options
author | Matthew Vogt <matthew.vogt@nokia.com> | 2012-03-23 14:16:43 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-08-27 05:17:13 +0200 |
commit | 965588737321d10fd1fbca3f89b4c6257b7b5d47 (patch) | |
tree | 95d069b6ce910c4f8bf8f71d50bebc4fe35a6b1f /src/qml/qml/v8 | |
parent | 4a161cfa0cf9167b575bdf7ff5685b9bf17c6960 (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.cpp | 8 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8qobjectwrapper.cpp | 57 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8qobjectwrapper_p.h | 20 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8typewrapper.cpp | 12 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8valuetypewrapper.cpp | 7 |
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) \ |