aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp4
-rw-r--r--src/qml/qml/qqmlcontext.cpp2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp1
-rw-r--r--tests/auto/qml/qqmlcontext/data/ContextLeak.js1
-rw-r--r--tests/auto/qml/qqmlcontext/data/contextLeak.qml5
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp37
6 files changed, 49 insertions, 1 deletions
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index d97d44379d..c7254e5989 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -138,7 +138,9 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
*hasProperty = true;
if (r.scriptIndex != -1) {
QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
- return scripts->getIndexed(r.scriptIndex);
+ if (scripts)
+ return scripts->getIndexed(r.scriptIndex);
+ return QV4::Encode::null();
} else if (r.type.isValid()) {
return QmlTypeWrapper::create(v4, scopeObject, r.type);
} else if (r.importNamespace) {
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 59e2c83a63..0c431b1260 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -579,6 +579,8 @@ void QQmlContextData::invalidate()
prevChild = 0;
}
+ importedScripts.clear();
+
engine = 0;
parent = 0;
}
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 19e57fbdba..5318375af7 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2917,6 +2917,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
m_program->qmlContext.set(scope.engine, qmlContext);
m_program->run();
+ m_program->qmlContext.clear();
if (scope.engine->hasException) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
if (error.isValid())
diff --git a/tests/auto/qml/qqmlcontext/data/ContextLeak.js b/tests/auto/qml/qqmlcontext/data/ContextLeak.js
new file mode 100644
index 0000000000..e43b1bb230
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/ContextLeak.js
@@ -0,0 +1 @@
+var value = 42
diff --git a/tests/auto/qml/qqmlcontext/data/contextLeak.qml b/tests/auto/qml/qqmlcontext/data/contextLeak.qml
new file mode 100644
index 0000000000..515b3a1aa2
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/contextLeak.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+import "ContextLeak.js" as ContextLeak
+QtObject {
+ property int value: ContextLeak.value
+}
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index 5f57b9ebb0..574e6e2834 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -33,6 +33,8 @@
#include <QQmlComponent>
#include <QQmlExpression>
#include <private/qqmlcontext_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4object_p.h>
#include "../../shared/util.h"
class tst_qqmlcontext : public QQmlDataTest
@@ -63,6 +65,7 @@ private slots:
void qobjectDerived();
void qtbug_49232();
void contextViaClosureAfterDestruction();
+ void contextLeak();
private:
QQmlEngine engine;
@@ -751,6 +754,40 @@ void tst_qqmlcontext::contextViaClosureAfterDestruction()
QCOMPARE(subObject.toString(), QLatin1String("Error: Qt.createQmlObject(): Cannot create a component in an invalid context"));
}
+void tst_qqmlcontext::contextLeak()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("contextLeak.qml"));
+
+ QQmlGuardedContextData scriptContext;
+
+ {
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 42);
+
+ QQmlData *ddata = QQmlData::get(obj.data());
+ QVERIFY(ddata);
+ QQmlContextData *context = ddata->context;
+ QVERIFY(context);
+ QVERIFY(!context->importedScripts.isNullOrUndefined());
+ QCOMPARE(int(context->importedScripts.valueRef()->as<QV4::Object>()->getLength()), 1);
+
+ {
+ QV4::Scope scope(ddata->jsWrapper.engine());
+ QV4::ScopedValue scriptContextWrapper(scope);
+ scriptContextWrapper = context->importedScripts.valueRef()->as<QV4::Object>()->getIndexed(0);
+ scriptContext = scriptContextWrapper->as<QV4::QmlContextWrapper>()->getContext();
+ }
+ }
+
+ engine.collectGarbage();
+
+ // Each time a JS file (non-pragma-shared) is imported, we create a QQmlContext(Data) for it.
+ // Make sure that context does not leak.
+ QVERIFY(scriptContext.isNull());
+}
+
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"