Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix memory leak with QtQuick compiler generated files
When for the QQC code path we do QML type re-compilation, we allocate a
new QV4::CompiledData::Unit. We must make sure that this dynamically
allocated memory is released in QV4::CompiledData::CompilationUnit's
destructor, by ensuring that the StaticData flag is not set.

This isn't directly applicable to the ahead-of-time generated cache file
unit data as they will always be re-generated (and thus the unsetting of
StaticData at the end of createCompilationUnit::createUnitData()), but
I've added a test-case nevertheless to ensure the correct engine
behavior.

Change-Id: I16973d7989567892bf8bf9dd6214bf293055d260
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
  • Loading branch information
tronical committed Feb 2, 2018
1 parent f7ffed9 commit 7bd5d93
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/qml/compiler/qqmlirbuilder.cpp
Expand Up @@ -1397,6 +1397,9 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(data);
qmlUnit->unitSize = totalSize;
qmlUnit->flags |= QV4::CompiledData::Unit::IsQml;
// This unit's memory was allocated with malloc on the heap, so it's
// definitely not suitable for StaticData access.
qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
qmlUnit->offsetToImports = unitSize;
qmlUnit->nImports = output.imports.count();
qmlUnit->offsetToObjects = unitSize + importSize;
Expand Down
18 changes: 18 additions & 0 deletions tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
Expand Up @@ -33,6 +33,7 @@
#include <QProcess>
#include <QLibraryInfo>
#include <QSysInfo>
#include <private/qqmlcomponent_p.h>

class tst_qmlcachegen: public QObject
{
Expand Down Expand Up @@ -114,13 +115,30 @@ void tst_qmlcachegen::loadGeneratedFile()

const QString cacheFilePath = testFilePath + QLatin1Char('c');
QVERIFY(QFile::exists(cacheFilePath));

{
QFile cache(cacheFilePath);
QVERIFY(cache.open(QIODevice::ReadOnly));
const QV4::CompiledData::Unit *cacheUnit = reinterpret_cast<const QV4::CompiledData::Unit *>(cache.map(/*offset*/0, sizeof(QV4::CompiledData::Unit)));
QVERIFY(cacheUnit);
QVERIFY(cacheUnit->flags & QV4::CompiledData::Unit::StaticData);
QVERIFY(cacheUnit->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
}

QVERIFY(QFile::remove(testFilePath));

QQmlEngine engine;
CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 42);

auto componentPrivate = QQmlComponentPrivate::get(&component);
QVERIFY(componentPrivate);
auto compilationUnit = componentPrivate->compilationUnit;
QVERIFY(compilationUnit);
QVERIFY(compilationUnit->data);
QVERIFY(!(compilationUnit->data->flags & QV4::CompiledData::Unit::StaticData));
}

void tst_qmlcachegen::translationExpressionSupport()
Expand Down

0 comments on commit 7bd5d93

Please sign in to comment.