From 3a5617dc45e281552b9c1f7a04f0561b8fa14d94 Mon Sep 17 00:00:00 2001 From: Andrei Golubev Date: Fri, 20 Nov 2020 10:44:44 +0100 Subject: Fix QML property cache leaks of delegate items The delegate items are destroyed through an event loop by a call to a deleteLater(). This, however, doesn't work when the application is in the process of exiting and the event loop is already closed (i.e. we're in a stack unwinding part that starts after app.exec()) Combat this situation by setting a parent of the to-be-deleted object to some QObject that will be destroyed e.g. QCoreApplication::instance() before the program finishes. As QObjects clean their children on destruction, this will make sure that we cleanup the previously leaking thing regardless of the event loop Added a test to check that delegates are destroyed (as a separate binary due to differences in main() function) Fixes: QTBUG-87228 Pick-to: 6.0 5.15 Change-Id: I59066603b77497fe4fd8d051798c3e4b47c119f0 Reviewed-by: Fabian Kosmale --- tests/auto/quick/CMakeLists.txt | 1 + tests/auto/quick/qquickview_extra/CMakeLists.txt | 39 +++++++++++ .../quick/qquickview_extra/data/qtbug_87228.qml | 30 +++++++++ .../quick/qquickview_extra/qquickview_extra.pro | 9 +++ .../qquickview_extra/tst_qquickview_extra.cpp | 77 ++++++++++++++++++++++ 5 files changed, 156 insertions(+) create mode 100644 tests/auto/quick/qquickview_extra/CMakeLists.txt create mode 100644 tests/auto/quick/qquickview_extra/data/qtbug_87228.qml create mode 100644 tests/auto/quick/qquickview_extra/qquickview_extra.pro create mode 100644 tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp (limited to 'tests/auto/quick') diff --git a/tests/auto/quick/CMakeLists.txt b/tests/auto/quick/CMakeLists.txt index 838d0917fb..70574110ed 100644 --- a/tests/auto/quick/CMakeLists.txt +++ b/tests/auto/quick/CMakeLists.txt @@ -60,6 +60,7 @@ if(QT_FEATURE_private_tests) add_subdirectory(qquicktextinput) add_subdirectory(qquickvisualdatamodel) add_subdirectory(qquickview) + add_subdirectory(qquickview_extra) add_subdirectory(qquickcanvasitem) add_subdirectory(qquickdesignersupport) add_subdirectory(qquickscreen) diff --git a/tests/auto/quick/qquickview_extra/CMakeLists.txt b/tests/auto/quick/qquickview_extra/CMakeLists.txt new file mode 100644 index 0000000000..16cc36a127 --- /dev/null +++ b/tests/auto/quick/qquickview_extra/CMakeLists.txt @@ -0,0 +1,39 @@ +# Generated from qquickview.pro. + +##################################################################### +## tst_qquickview_extra Test: +##################################################################### + +# Collect test data +file(GLOB_RECURSE test_data_glob + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + data/*) +list(APPEND test_data ${test_data_glob}) + +qt_internal_add_test(tst_qquickview_extra + SOURCES + ../../shared/util.cpp ../../shared/util.h + tst_qquickview_extra.cpp + DEFINES + QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\" + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::GuiPrivate + Qt::QmlPrivate + Qt::QuickPrivate + TESTDATA ${test_data} +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_qquickview_extra CONDITION ANDROID OR IOS + DEFINES + QT_QMLTEST_DATADIR=\\\":/data\\\" +) + +qt_internal_extend_target(tst_qquickview_extra CONDITION NOT ANDROID AND NOT IOS + DEFINES + QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\" +) diff --git a/tests/auto/quick/qquickview_extra/data/qtbug_87228.qml b/tests/auto/quick/qquickview_extra/data/qtbug_87228.qml new file mode 100644 index 0000000000..ff10eba23d --- /dev/null +++ b/tests/auto/quick/qquickview_extra/data/qtbug_87228.qml @@ -0,0 +1,30 @@ +import QtQml 2.12 +import QtQml.Models 2.12 +import QtQuick 2.12 + +Item { + height: 480 + width: 320 + Rectangle { + id: rootRect + + function addItem(desc) { + myModel.append({"desc": desc}); + } + + Rectangle { + ListView { + objectName: "listView" + delegate: Text { + required property string desc + text: desc + } + model: ListModel { id: myModel } + } + } + + Component.onCompleted: { + addItem("Test creation of a delegate with a property"); + } + } +} diff --git a/tests/auto/quick/qquickview_extra/qquickview_extra.pro b/tests/auto/quick/qquickview_extra/qquickview_extra.pro new file mode 100644 index 0000000000..6cee00f387 --- /dev/null +++ b/tests/auto/quick/qquickview_extra/qquickview_extra.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qquickview_extra +macx:CONFIG -= app_bundle + +SOURCES += tst_qquickview_extra.cpp + +TESTDATA = data/* + +QT += core-private gui-private qml-private quick-private testlib diff --git a/tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp b/tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp new file mode 100644 index 0000000000..f697a438bd --- /dev/null +++ b/tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include "../../shared/util.h" +#include +#include + +// Extra app-less tests +class tst_QQuickViewExtra : public QQmlDataTest +{ + Q_OBJECT +public: + tst_QQuickViewExtra(); + +private slots: + void qtbug_87228(); +}; + +tst_QQuickViewExtra::tst_QQuickViewExtra() { } + +void tst_QQuickViewExtra::qtbug_87228() +{ + QScopedPointer deletionSpy; + { + int argc = 0; + QGuiApplication app(argc, nullptr); + QQuickView view; + + view.setSource(testFileUrl("qtbug_87228.qml")); + view.show(); + QTimer::singleShot(500, &app, QCoreApplication::quit); + app.exec(); + + QObject *listView = view.findChild("listView"); + QVERIFY(listView); + QQuickItem *contentItem = listView->property("contentItem").value(); + QVERIFY(contentItem); + auto children = contentItem->childItems(); + QVERIFY(children.size() > 0); + // for the sake of this test, any child would be suitable, so pick first + deletionSpy.reset(new QSignalSpy(children[0], SIGNAL(destroyed(QObject *)))); + } + QCOMPARE(deletionSpy->count(), 1); +} + +QTEST_APPLESS_MAIN(tst_QQuickViewExtra) + +#include "tst_qquickview_extra.moc" -- cgit v1.2.3