aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-11-02 17:08:16 +0000
committerQt by Nokia <qt-info@nokia.com>2011-11-04 13:00:47 +0100
commit4a8871d3fe6c9fe16752697abf95d3a7b8fba7b7 (patch)
treee7c7d5dcefe2bdebe6d7aeb58ffcda6f5572c4c8 /src
parentf9261feb16d02e985982dd46783ea54c2cfce91b (diff)
Don't crash if contexts are deleted during refreshExpressions
Change-Id: I23b59d33c07b017ef7355a7fe4a728d84c5d7eaa Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/declarative/qml/ftw/ftw.pri1
-rw-r--r--src/declarative/qml/ftw/qdeletewatcher_p.h113
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp2
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp87
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h2
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp2
-rw-r--r--src/declarative/qml/qdeclarativeexpression_p.h57
-rw-r--r--src/declarative/qml/qdeclarativeproperty.cpp2
-rw-r--r--src/declarative/qml/v8/qv8bindings.cpp2
9 files changed, 196 insertions, 72 deletions
diff --git a/src/declarative/qml/ftw/ftw.pri b/src/declarative/qml/ftw/ftw.pri
index 63399927e7..9d114e2b05 100644
--- a/src/declarative/qml/ftw/ftw.pri
+++ b/src/declarative/qml/ftw/ftw.pri
@@ -11,6 +11,7 @@ HEADERS += \
$$PWD/qdeclarativethread_p.h \
$$PWD/qfinitestack_p.h \
$$PWD/qrecursionwatcher_p.h \
+ $$PWD/qdeletewatcher_p.h \
$$PWD/qrecyclepool_p.h \
SOURCES += \
diff --git a/src/declarative/qml/ftw/qdeletewatcher_p.h b/src/declarative/qml/ftw/qdeletewatcher_p.h
new file mode 100644
index 0000000000..34ef46bc17
--- /dev/null
+++ b/src/declarative/qml/ftw/qdeletewatcher_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDELETEWATCHER_P_H
+#define QDELETEWATCHER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeleteWatchable
+{
+public:
+ inline QDeleteWatchable();
+ inline ~QDeleteWatchable();
+private:
+ friend class QDeleteWatcher;
+ bool *_w;
+};
+
+class QDeleteWatcher {
+public:
+ inline QDeleteWatcher(QDeleteWatchable *data);
+ inline ~QDeleteWatcher();
+ inline bool wasDeleted() const;
+private:
+ void *operator new(size_t);
+ bool *_w;
+ bool _s;
+ QDeleteWatchable *m_d;
+};
+
+QDeleteWatchable::QDeleteWatchable()
+: _w(0)
+{
+}
+
+QDeleteWatchable::~QDeleteWatchable()
+{
+ if (_w) *_w = true;
+}
+
+QDeleteWatcher::QDeleteWatcher(QDeleteWatchable *data)
+: _s(false), m_d(data)
+{
+ if (!m_d->_w)
+ m_d->_w = &_s;
+ _w = m_d->_w;
+}
+
+QDeleteWatcher::~QDeleteWatcher()
+{
+ if (false == *_w && &_s == m_d->_w)
+ m_d->_w = 0;
+}
+
+bool QDeleteWatcher::wasDeleted() const
+{
+ return *_w;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDELETEWATCHER_P_H
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index 531842a695..9a3a7e005c 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -345,7 +345,7 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
QDeclarativeBindingProfiler prof(this);
d->updating = true;
- QDeclarativeDeleteWatcher watcher(d);
+ QDeleteWatcher watcher(d);
if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index c4fc764e7d..d7a642460c 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -653,23 +653,82 @@ void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentT
}
}
-/*
-Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
-context-tree dependent caches in the expressions, and should occur every time the context tree
- *structure* (not values) changes.
-*/
-void QDeclarativeContextData::refreshExpressions()
+void QDeclarativeContextData::refreshExpressionsRecursive(QDeclarativeAbstractExpression *expression)
{
- QDeclarativeContextData *child = childContexts;
- while (child) {
- child->refreshExpressions();
- child = child->nextChild;
- }
+ QDeleteWatcher w(expression);
- QDeclarativeAbstractExpression *expression = expressions;
- while (expression) {
+ if (expression->m_nextExpression)
+ refreshExpressionsRecursive(expression->m_nextExpression);
+
+ if (!w.wasDeleted())
expression->refresh();
- expression = expression->m_nextExpression;
+}
+
+void QDeclarativeContextData::refreshExpressionsRecursive()
+{
+ // For efficiency, we try and minimize the number of guards we have to create
+ if (expressions && (nextChild || childContexts)) {
+ QDeclarativeGuardedContextData guard(this);
+
+ if (childContexts)
+ childContexts->refreshExpressionsRecursive();
+
+ if (guard.isNull()) return;
+
+ if (nextChild)
+ nextChild->refreshExpressionsRecursive();
+
+ if (guard.isNull()) return;
+
+ if (expressions)
+ refreshExpressionsRecursive(expressions);
+
+ } else if (expressions) {
+
+ refreshExpressionsRecursive(expressions);
+
+ } else if (nextChild && childContexts) {
+
+ QDeclarativeGuardedContextData guard(this);
+
+ childContexts->refreshExpressionsRecursive();
+
+ if (!guard.isNull() && nextChild)
+ nextChild->refreshExpressionsRecursive();
+
+ } else if (nextChild) {
+
+ nextChild->refreshExpressionsRecursive();
+
+ } else if (childContexts) {
+
+ childContexts->refreshExpressionsRecursive();
+
+ }
+}
+
+// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
+// context-tree dependent caches in the expressions, and should occur every time the context tree
+// *structure* (not values) changes.
+void QDeclarativeContextData::refreshExpressions()
+{
+ // For efficiency, we try and minimize the number of guards we have to create
+ if (expressions && childContexts) {
+ QDeclarativeGuardedContextData guard(this);
+
+ childContexts->refreshExpressionsRecursive();
+
+ if (!guard.isNull() && expressions)
+ refreshExpressionsRecursive(expressions);
+
+ } else if (expressions) {
+
+ refreshExpressionsRecursive(expressions);
+
+ } else if (childContexts) {
+
+ childContexts->refreshExpressionsRecursive();
+
}
}
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index a6e83a0692..6676a0693c 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -216,6 +216,8 @@ public:
}
private:
+ void refreshExpressionsRecursive();
+ void refreshExpressionsRecursive(QDeclarativeAbstractExpression *);
~QDeclarativeContextData() {}
};
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index fa899cf814..b178045d44 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -434,7 +434,7 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F
// All code that follows must check with watcher before it accesses data members
// incase we have been deleted.
- QDeclarativeDeleteWatcher watcher(this);
+ QDeleteWatcher watcher(this);
if (sharedContext) {
lastSharedContext = ep->sharedContext;
diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h
index 65b07ca7e8..bfe031fbc8 100644
--- a/src/declarative/qml/qdeclarativeexpression_p.h
+++ b/src/declarative/qml/qdeclarativeexpression_p.h
@@ -57,12 +57,13 @@
#include <private/qv8engine_p.h>
#include <private/qfieldlist_p.h>
+#include <private/qdeletewatcher_p.h>
#include <private/qdeclarativeguard_p.h>
#include <private/qdeclarativeengine_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeAbstractExpression
+class QDeclarativeAbstractExpression : public QDeleteWatchable
{
public:
QDeclarativeAbstractExpression();
@@ -107,31 +108,8 @@ private:
QDeclarativeDelayedError **prevError;
};
-class QDeclarativeDeleteWatchable
-{
-public:
- inline QDeclarativeDeleteWatchable();
- inline ~QDeclarativeDeleteWatchable();
-private:
- friend class QDeclarativeDeleteWatcher;
- bool *m_wasDeleted;
-};
-
-class QDeclarativeDeleteWatcher {
-public:
- inline QDeclarativeDeleteWatcher(QDeclarativeDeleteWatchable *data);
- inline ~QDeclarativeDeleteWatcher();
- inline bool wasDeleted() const;
-private:
- void *operator new(size_t);
- bool *m_wasDeleted;
- bool m_wasDeletedStorage;
- QDeclarativeDeleteWatchable *m_d;
-};
-
class QDeclarativeJavaScriptExpression : public QDeclarativeAbstractExpression,
- public QDeclarativeDelayedError,
- public QDeclarativeDeleteWatchable
+ public QDeclarativeDelayedError
{
public:
QDeclarativeJavaScriptExpression();
@@ -233,35 +211,6 @@ public:
QDeclarativeRefCount *dataRef;
};
-QDeclarativeDeleteWatchable::QDeclarativeDeleteWatchable()
-: m_wasDeleted(0)
-{
-}
-
-QDeclarativeDeleteWatchable::~QDeclarativeDeleteWatchable()
-{
- if (m_wasDeleted) *m_wasDeleted = true;
-}
-
-QDeclarativeDeleteWatcher::QDeclarativeDeleteWatcher(QDeclarativeDeleteWatchable *data)
-: m_wasDeletedStorage(false), m_d(data)
-{
- if (!m_d->m_wasDeleted)
- m_d->m_wasDeleted = &m_wasDeletedStorage;
- m_wasDeleted = m_d->m_wasDeleted;
-}
-
-QDeclarativeDeleteWatcher::~QDeclarativeDeleteWatcher()
-{
- if (false == *m_wasDeleted && m_wasDeleted == m_d->m_wasDeleted)
- m_d->m_wasDeleted = 0;
-}
-
-bool QDeclarativeDeleteWatcher::wasDeleted() const
-{
- return *m_wasDeleted;
-}
-
bool QDeclarativeJavaScriptExpression::requiresThisObject() const
{
return m_requiresThisObject;
diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp
index c630de4040..d6a2776b32 100644
--- a/src/declarative/qml/qdeclarativeproperty.cpp
+++ b/src/declarative/qml/qdeclarativeproperty.cpp
@@ -1348,7 +1348,7 @@ bool QDeclarativePropertyPrivate::writeBinding(QObject *object,
int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
- QDeclarativeDeleteWatcher watcher(expression);
+ QDeleteWatcher watcher(expression);
QVariant value;
bool isVmeProperty = core.isVMEProperty();
diff --git a/src/declarative/qml/v8/qv8bindings.cpp b/src/declarative/qml/v8/qv8bindings.cpp
index 57411ae525..271267d851 100644
--- a/src/declarative/qml/v8/qv8bindings.cpp
+++ b/src/declarative/qml/v8/qv8bindings.cpp
@@ -85,7 +85,7 @@ void QV8Bindings::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
bool isUndefined = false;
- QDeclarativeDeleteWatcher watcher(this);
+ QDeleteWatcher watcher(this);
ep->referenceScarceResources();
v8::HandleScope handle_scope;