Fix crash in listmodel when data is assigned incorrectly.
authorGlenn Watson <glenn.watson@nokia.com>
Thu, 8 Mar 2012 23:19:35 +0000 (09:19 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 9 Mar 2012 08:56:25 +0000 (09:56 +0100)
If a listmodel with static role types is created, it would crash
if a role was assigned a value type such as string, and then
subsequently assigned an array (sub list) value from a dynamic
meta object (created when using get() from JS).

Change-Id: Ibfd0b0b40be13b04103b49462cfae42a5c9f9fb9
Reviewed-by: Martin Jones <martin.jones@nokia.com>
src/qml/qml/qquicklistmodel.cpp
tests/auto/qml/qquicklistmodel/tst_qquicklistmodel.cpp

index 30c4f5d..48187ca 100644 (file)
@@ -1110,14 +1110,18 @@ int ListElement::setJsProperty(const ListLayout::Role &role, v8::Handle<v8::Valu
     } else if (d->IsNumber()) {
         roleIndex = setDoubleProperty(role, d->NumberValue());
     } else if (d->IsArray()) {
-        ListModel *subModel = new ListModel(role.subLayout, 0, -1);
-        v8::Handle<v8::Array> subArray = v8::Handle<v8::Array>::Cast(d);
-        int arrayLength = subArray->Length();
-        for (int j=0 ; j < arrayLength ; ++j) {
-            v8::Handle<v8::Object> subObject = subArray->Get(j)->ToObject();
-            subModel->append(subObject, eng);
+        if (role.type == ListLayout::Role::List) {
+            ListModel *subModel = new ListModel(role.subLayout, 0, -1);
+            v8::Handle<v8::Array> subArray = v8::Handle<v8::Array>::Cast(d);
+            int arrayLength = subArray->Length();
+            for (int j=0 ; j < arrayLength ; ++j) {
+                v8::Handle<v8::Object> subObject = subArray->Get(j)->ToObject();
+                subModel->append(subObject, eng);
+            }
+            roleIndex = setListProperty(role, subModel);
+        } else {
+            qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List));
         }
-        roleIndex = setListProperty(role, subModel);
     } else if (d->IsBoolean()) {
         roleIndex = setBoolProperty(role, d->BooleanValue());
     } else if (d->IsObject()) {
index 3fcce60..69a8d2e 100644 (file)
@@ -139,6 +139,7 @@ private slots:
     void role_mode();
     void dynamic_role();
     void dynamic_role_data();
+    void string_to_list_crash();
 };
 
 bool tst_qquicklistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -1627,6 +1628,19 @@ void tst_qquicklistmodel::dynamic_role()
     qApp->processEvents();
 }
 
+void tst_qquicklistmodel::string_to_list_crash()
+{
+    QQmlEngine engine;
+    QQuickListModel model;
+    QQmlEngine::setContextForObject(&model,engine.rootContext());
+    engine.rootContext()->setContextObject(&model);
+    QString script = QLatin1String("{append({'a':'data'});get(0).a = [{'x':123}]}");
+    QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Can't assign to existing role 'a' of different type [String -> List]");
+    QQmlExpression e(engine.rootContext(), &model, script);
+    // Don't crash!
+    e.evaluate();
+}
+
 QTEST_MAIN(tst_qquicklistmodel)
 
 #include "tst_qquicklistmodel.moc"