diff options
-rw-r--r-- | src/qml/jsruntime/qv4qmlcontext.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontext.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/data/ContextLeak.js | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/data/contextLeak.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 37 |
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" |