From 5bd0e08063fcacba0c2b63528712968c7d74e7f9 Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Thu, 27 Sep 2012 16:56:03 +0200 Subject: Fix a crash in QQmlPropertyCache::findProperty 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 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlvmemetaobject.cpp | 52 +++++++++++++++++++++------------------ src/qml/qml/qqmlvmemetaobject_p.h | 2 +- 2 files changed, 29 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 37d72f16b3..14d25b6a5e 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -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(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 QQmlVMEMetaObject::vmeMethod(int index) { if (index < methodOffset()) { - Q_ASSERT(parent.isT1()); - return static_cast(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 QQmlVMEMetaObject::vmeMethod(int index) void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent value) { if (index < methodOffset()) { - Q_ASSERT(parent.isT1()); - return static_cast(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 val v8::Handle QQmlVMEMetaObject::vmeProperty(int index) { if (index < propOffset()) { - Q_ASSERT(parent.isT1()); - return static_cast(parent.asT1())->vmeProperty(index); + Q_ASSERT(parentVMEMetaObject()); + return parentVMEMetaObject()->vmeProperty(index); } return readVarProperty(index - propOffset()); } @@ -1209,8 +1213,8 @@ v8::Handle QQmlVMEMetaObject::vmeProperty(int index) void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle v) { if (index < propOffset()) { - Q_ASSERT(parent.isT1()); - static_cast(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(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(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(vme->parent.asT1()); - } + while (vme && vme->signalOffset() > coreIndex) + vme = vme->parentVMEMetaObject(); + + Q_ASSERT(vme); return vme; } diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index 8329e3ce16..c858370d27 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -287,7 +287,7 @@ int QQmlVMEMetaObject::signalCount() const QQmlVMEMetaObject *QQmlVMEMetaObject::parentVMEMetaObject() const { - if (parent.isT1()) + if (parent.isT1() && parent.flag()) return static_cast(parent.asT1()); return 0; -- cgit v1.2.3