Deleting an incubated object after setInitialState() crashes
authorMartin Jones <martin.jones@nokia.com>
Tue, 29 Nov 2011 23:44:13 +0000 (09:44 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 30 Nov 2011 03:34:34 +0000 (04:34 +0100)
Incubating objects are often parented in setInitialState(), which
can lead to the incubating object being deleted after object creation,
but before completion.  When incubator.clear() is called after
this point, it would attempt to delete the already deleted
object. This change guards the incubation object in the incubator.

Change-Id: I9585e93027250b8b6b3f1777b10ee1008ae7b818
Reviewed-by: Glenn Watson <glenn.watson@nokia.com>

src/declarative/qml/qdeclarativeincubator_p.h
tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp

index ebabbae..8f76239 100644 (file)
@@ -83,7 +83,7 @@ public:
     enum Progress { Execute, Completing, Completed };
     Progress progress;
 
-    QObject *result;
+    QDeclarativeGuard<QObject> result;
     QDeclarativeGuardedContextData rootContext;
     QDeclarativeCompiledData *component;
     QDeclarativeVME vme;
index 74a6b83..fe618b8 100644 (file)
@@ -79,6 +79,7 @@ private slots:
     void forceCompletion();
     void setInitialState();
     void clearDuringCompletion();
+    void objectDeletionAfterInit();
     void recursiveClear();
     void statusChanged();
     void asynchronousIfNested();
@@ -434,6 +435,42 @@ void tst_qdeclarativeincubator::clearDuringCompletion()
     QVERIFY(srt.isNull());
 }
 
+void tst_qdeclarativeincubator::objectDeletionAfterInit()
+{
+    QDeclarativeComponent component(&engine, TEST_FILE("clear.qml"));
+    QVERIFY(component.isReady());
+
+    struct MyIncubator : public QDeclarativeIncubator
+    {
+        MyIncubator(QDeclarativeIncubator::IncubationMode mode)
+        : QDeclarativeIncubator(mode), obj(0) {}
+
+        virtual void setInitialState(QObject *o) {
+            obj = o;
+        }
+
+        QObject *obj;
+    };
+
+    SelfRegisteringType::clearMe();
+    MyIncubator incubator(QDeclarativeIncubator::Asynchronous);
+    component.create(incubator);
+
+    while (!incubator.obj && incubator.isLoading()) {
+        bool b = false;
+        controller.incubateWhile(&b);
+    }
+
+    QVERIFY(incubator.isLoading());
+    QVERIFY(SelfRegisteringType::me() != 0);
+
+    delete incubator.obj;
+
+    incubator.clear();
+    QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+    QVERIFY(incubator.isNull());
+}
+
 class Switcher : public QObject
 {
     Q_OBJECT