Fix a crash in QQmlPropertyCache::findProperty
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>
Thu, 27 Sep 2012 14:56:03 +0000 (16:56 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 28 Sep 2012 11:26:16 +0000 (13:26 +0200)
When the top type of a QML component is a C++ type registered with
qmlRegisterExtendedType, its QObjectPrivate::metaObject is already a
QQmlProxyMetaObject that gets chained as the parent of the
QQmlVMEMetaObject of the component.

When QQmlPropertyCache::findProperty iterates over the parents chain
of a child item, our QQmlProxyMetaObject eventually gets static_casted
to QQmlVMEMetaObject and causes a crash.

This patch implements a poor man's dynamic_cast in
QQmlVMEMetaObject::parentVMEMetaObject to fix the crash. Other casts
of parent.asT1() are changed to use parentVMEMetaObject as well even
though in those cases the static_cast is guaranteed by the context.

Task-number: QTBUG-27334
Change-Id: I5982fc273ccf466960ce54974cff5662e6ab605a
Reviewed-by: Matthew Vogt <mattvogt2@gmail.com>
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/qml/qml/qqmlvmemetaobject.cpp
src/qml/qml/qqmlvmemetaobject_p.h

index 37d72f1..14d25b6 100644 (file)
@@ -559,8 +559,12 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
 {
     QObjectPrivate *op = QObjectPrivate::get(obj);
 
-    if (op->metaObject) parent = op->metaObject;
-    else parent = obj->metaObject();
+    if (op->metaObject) {
+        parent = op->metaObject;
+        // Use the extra flag in QBiPointer to know if we can safely cast parent.asT1() to QQmlVMEMetaObject*
+        parent.setFlagValue(QQmlData::get(obj)->hasVMEMetaObject);
+    } else
+        parent = obj->metaObject();
 
     op->metaObject = this;
     QQmlData::get(obj)->hasVMEMetaObject = true;
@@ -1154,8 +1158,8 @@ void QQmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QQmlPrope
 quint16 QQmlVMEMetaObject::vmeMethodLineNumber(int index)
 {
     if (index < methodOffset()) {
-        Q_ASSERT(parent.isT1());
-        return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeMethodLineNumber(index);
+        Q_ASSERT(parentVMEMetaObject());
+        return parentVMEMetaObject()->vmeMethodLineNumber(index);
     }
 
     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
@@ -1170,8 +1174,8 @@ quint16 QQmlVMEMetaObject::vmeMethodLineNumber(int index)
 v8::Handle<v8::Function> QQmlVMEMetaObject::vmeMethod(int index)
 {
     if (index < methodOffset()) {
-        Q_ASSERT(parent.isT1());
-        return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeMethod(index);
+        Q_ASSERT(parentVMEMetaObject());
+        return parentVMEMetaObject()->vmeMethod(index);
     }
     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
     Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
@@ -1182,8 +1186,8 @@ v8::Handle<v8::Function> QQmlVMEMetaObject::vmeMethod(int index)
 void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value)
 {
     if (index < methodOffset()) {
-        Q_ASSERT(parent.isT1());
-        return static_cast<QQmlVMEMetaObject *>(parent.asT1())->setVmeMethod(index, value);
+        Q_ASSERT(parentVMEMetaObject());
+        return parentVMEMetaObject()->setVmeMethod(index, value);
     }
     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
     Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
@@ -1200,8 +1204,8 @@ void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> val
 v8::Handle<v8::Value> QQmlVMEMetaObject::vmeProperty(int index)
 {
     if (index < propOffset()) {
-        Q_ASSERT(parent.isT1());
-        return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeProperty(index);
+        Q_ASSERT(parentVMEMetaObject());
+        return parentVMEMetaObject()->vmeProperty(index);
     }
     return readVarProperty(index - propOffset());
 }
@@ -1209,8 +1213,8 @@ v8::Handle<v8::Value> QQmlVMEMetaObject::vmeProperty(int index)
 void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v)
 {
     if (index < propOffset()) {
-        Q_ASSERT(parent.isT1());
-        static_cast<QQmlVMEMetaObject *>(parent.asT1())->setVMEProperty(index, v);
+        Q_ASSERT(parentVMEMetaObject());
+        parentVMEMetaObject()->setVMEProperty(index, v);
         return;
     }
     return writeVarProperty(index - propOffset(), v);
@@ -1351,20 +1355,20 @@ void QQmlVMEMetaObject::activate(QObject *object, int index, void **args)
 QQmlVMEMetaObject *QQmlVMEMetaObject::getForProperty(QObject *o, int coreIndex)
 {
     QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
-    while (vme->propOffset() > coreIndex) {
-        Q_ASSERT(vme->parent.isT1());
-        vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1());
-    }
+    while (vme && vme->propOffset() > coreIndex)
+        vme = vme->parentVMEMetaObject();
+
+    Q_ASSERT(vme);
     return vme;
 }
 
 QQmlVMEMetaObject *QQmlVMEMetaObject::getForMethod(QObject *o, int coreIndex)
 {
     QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
-    while (vme->methodOffset() > coreIndex) {
-        Q_ASSERT(vme->parent.isT1());
-        vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1());
-    }
+    while (vme && vme->methodOffset() > coreIndex)
+        vme = vme->parentVMEMetaObject();
+
+    Q_ASSERT(vme);
     return vme;
 }
 
@@ -1375,10 +1379,10 @@ QQmlVMEMetaObject *QQmlVMEMetaObject::getForMethod(QObject *o, int coreIndex)
 QQmlVMEMetaObject *QQmlVMEMetaObject::getForSignal(QObject *o, int coreIndex)
 {
     QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
-    while (vme->signalOffset() > coreIndex) {
-        Q_ASSERT(vme->parent.isT1());
-        vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1());
-    }
+    while (vme && vme->signalOffset() > coreIndex)
+        vme = vme->parentVMEMetaObject();
+
+    Q_ASSERT(vme);
     return vme;
 }
 
index 8329e3c..c858370 100644 (file)
@@ -287,7 +287,7 @@ int QQmlVMEMetaObject::signalCount() const
 
 QQmlVMEMetaObject *QQmlVMEMetaObject::parentVMEMetaObject() const
 {
-    if (parent.isT1())
+    if (parent.isT1() && parent.flag())
         return static_cast<QQmlVMEMetaObject *>(parent.asT1());
 
     return 0;