Fix crash in object serialization due to sequences
authorChris Adams <christopher.adams@nokia.com>
Fri, 4 Nov 2011 04:38:38 +0000 (14:38 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 4 Nov 2011 06:00:54 +0000 (07:00 +0100)
Commit c177691118e4e2bace9b5c1f4f57343190e6ad64 added support for
sequences, but in doing so, introduced a crash bug into worker thread
object serialisation.  This commit fixes the bug by ensuring that the
object resource type is checked prior to serialisation.

Change-Id: I4ef9e4d0865a337c4fe6e8f1cd40cf4462ca7a60
Reviewed-by: Martin Jones <martin.jones@nokia.com>

src/declarative/qml/v8/qv8worker.cpp
tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp

index 16e5abf..f0d9906 100644 (file)
@@ -257,23 +257,25 @@ void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *
         if (v->IsObject()) {
             v8::Handle<v8::Object> seqObj = v->ToObject();
             QV8ObjectResource *r = static_cast<QV8ObjectResource *>(seqObj->GetExternalResource());
-            QVariant sequenceVariant = engine->sequenceWrapper()->toVariant(r);
-            if (!sequenceVariant.isNull()) {
-                // valid sequence.  we generate a length (sequence length + 1 for the sequence type)
-                uint32_t seqLength = engine->sequenceWrapper()->sequenceLength(r);
-                uint32_t length = seqLength + 1;
-                if (length > 0xFFFFFF) {
-                    push(data, valueheader(WorkerUndefined));
+            if (r->resourceType() == QV8ObjectResource::SequenceType) {
+                QVariant sequenceVariant = engine->sequenceWrapper()->toVariant(r);
+                if (!sequenceVariant.isNull()) {
+                    // valid sequence.  we generate a length (sequence length + 1 for the sequence type)
+                    uint32_t seqLength = engine->sequenceWrapper()->sequenceLength(r);
+                    uint32_t length = seqLength + 1;
+                    if (length > 0xFFFFFF) {
+                        push(data, valueheader(WorkerUndefined));
+                        return;
+                    }
+                    reserve(data, sizeof(quint32) + length * sizeof(quint32));
+                    push(data, valueheader(WorkerSequence, length));
+                    serialize(data, v8::Integer::New(sequenceVariant.userType()), engine); // sequence type
+                    for (uint32_t ii = 0; ii < seqLength; ++ii) {
+                        serialize(data, seqObj->Get(ii), engine); // sequence elements
+                    }
+
                     return;
                 }
-                reserve(data, sizeof(quint32) + length * sizeof(quint32));
-                push(data, valueheader(WorkerSequence, length));
-                serialize(data, v8::Integer::New(sequenceVariant.userType()), engine); // sequence type
-                for (uint32_t ii = 0; ii < seqLength; ++ii) {
-                    serialize(data, seqObj->Get(ii), engine); // sequence elements
-                }
-
-                return;
             }
         }
 
diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml b/tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml
new file mode 100644 (file)
index 0000000..1dae608
--- /dev/null
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+    id: root
+
+    function testExternalObject() {
+        worker.sendMessage(Qt.vector3d(1,2,3));
+    }
+
+    WorkerScript {
+        id: worker
+        source: "script.js"
+    }
+}
index bb7921c..eb3413e 100644 (file)
@@ -69,6 +69,7 @@ private slots:
     void messaging_data();
     void messaging_sendQObjectList();
     void messaging_sendJsObject();
+    void messaging_sendExternalObject();
     void script_with_pragma();
     void script_included();
     void scriptError_onLoad();
@@ -200,6 +201,16 @@ void tst_QDeclarativeWorkerScript::messaging_sendJsObject()
     delete worker;
 }
 
+void tst_QDeclarativeWorkerScript::messaging_sendExternalObject()
+{
+    QDeclarativeComponent component(&m_engine, TESTDATA("externalObjectWorker.qml"));
+    QObject *obj = component.create();
+    QVERIFY(obj);
+    QMetaObject::invokeMethod(obj, "testExternalObject");
+    QTest::qWait(100); // shouldn't crash.
+    delete obj;
+}
+
 void tst_QDeclarativeWorkerScript::script_with_pragma()
 {
     QVariant value(100);