Don't crash with deferred properties

There are cases where a qmlExecuteDeferred(o) can be postponed until the
context of o is being destroyed, at which point it's too late to create
an object in that context.

Task-number: QTBUG-33112
Change-Id: I7f981b5e34e3cb8a52c00de4742a7242d7e4df54
Reviewed-by: Christopher Adams <chris.adams@jollamobile.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Alan Alpert 2013-08-21 13:21:03 -07:00 committed by The Qt Project
parent da91b1c731
commit fac5337abf
5 changed files with 50 additions and 1 deletions

View File

@ -1287,7 +1287,7 @@ void qmlExecuteDeferred(QObject *object)
{
QQmlData *data = QQmlData::get(object);
if (data && data->deferredData) {
if (data && data->deferredData && !data->wasDeleted(object)) {
QQmlObjectCreatingProfiler prof;
if (prof.enabled) {
QQmlType *type = QQmlMetaType::qmlType(object->metaObject());

View File

@ -0,0 +1,6 @@
import Qt.test 1.0
MyVeryDeferredObject {
id: root
objectProperty: MyQmlObject { }
}

View File

@ -252,6 +252,7 @@ void registerTypes()
qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObjectAlias");
qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObject");
qmlRegisterType<MyDeferredObject>("Qt.test", 1,0, "MyDeferredObject");
qmlRegisterType<MyVeryDeferredObject>("Qt.test", 1,0, "MyVeryDeferredObject");
qmlRegisterType<MyQmlContainer>("Qt.test", 1,0, "MyQmlContainer");
qmlRegisterExtendedType<MyBaseExtendedObject, BaseExtensionObject>("Qt.test", 1,0, "MyBaseExtendedObject");
qmlRegisterExtendedType<MyExtendedObject, ExtensionObject>("Qt.test", 1,0, "MyExtendedObject");

View File

@ -376,6 +376,34 @@ private:
QObject *m_object2;
};
class MyVeryDeferredObject : public QObject
{
Q_OBJECT
//For inDestruction test
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty)
Q_CLASSINFO("DeferredPropertyNames", "objectProperty")
public:
MyVeryDeferredObject() : m_value(0), m_object(0) {}
~MyVeryDeferredObject() {
qmlExecuteDeferred(this); //Not a realistic case, see QTBUG-33112 to see how this could happen in practice
}
int value() const { return m_value; }
void setValue(int v) { m_value = v; emit valueChanged(); }
QObject *objectProperty() const { return m_object; }
void setObjectProperty(QObject *obj) { m_object = obj; }
signals:
void valueChanged();
private:
int m_value;
QObject *m_object;
};
class MyBaseExtendedObject : public QObject
{
Q_OBJECT

View File

@ -102,6 +102,7 @@ private slots:
void deferredProperties();
void deferredPropertiesErrors();
void deferredPropertiesInComponents();
void deferredPropertiesInDestruction();
void extensionObjects();
void overrideExtensionProperties();
void attachedProperties();
@ -924,6 +925,19 @@ void tst_qqmlecmascript::deferredPropertiesInComponents()
delete object;
}
void tst_qqmlecmascript::deferredPropertiesInDestruction()
{
//Test that the component does not get created at all if creation is deferred until the containing context is destroyed
//Very specific operation ordering is needed for this to occur, currently accessing object from object destructor.
//
QQmlComponent component(&engine, testFileUrl("deferredPropertiesInDestruction.qml"));
QObject *object = component.create();
if (!object)
qDebug() << component.errorString();
QVERIFY(object != 0);
delete object; //QTBUG-33112 was that this used to cause a crash
}
void tst_qqmlecmascript::extensionObjects()
{
QQmlComponent component(&engine, testFileUrl("extensionObjects.qml"));