Bug#983597: Segfault in libqt5quick5.so: QQuickItemLayer::~QQuickItemLayer()
This may have gotten fixed by the fix for QTBUG-107850[1] (commit
7487332)[2]. QTBUG-84858 gets a tacit mention there, but is not among
the list of duplicates that got closed through this (even though it
probably should be).
I hastily backported this to 5.15.8 (see attachment), but have not yet
checked if it actually compiles (the test might use functions/macros
missing from 5.15) or works. I can't look into this more currently
since I'm somewhat busy. Hopefully I can try it out this weekend.
Regards.
1: https://bugreports.qt.io/browse/QTBUG-107850
2: https://invent.kde.org/qt/qt/qtdeclarative/-/commit/74873324bdf3399753f9fcaf7461c0e00df628b1
Description: backport commit 7487332 to hopefully fix #983597
Edited from the original for 6.5.0 FF: https://invent.kde.org/qt/qt/qtdeclarative/-/commit/74873324bdf3399753f9fcaf7461c0e00df628b1
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2326,6 +2326,7 @@
QQuickItem::~QQuickItem()
{
Q_D(QQuickItem);
+ d->inDestructor = true;
if (d->windowRefCount > 1)
d->windowRefCount = 1; // Make sure window is set to null in next call to derefWindow().
@@ -2689,9 +2690,8 @@
const bool wasVisible = isVisible();
op->removeChild(this);
- if (wasVisible) {
+ if (wasVisible && !op->inDestructor)
emit oldParentItem->visibleChildrenChanged();
- }
} else if (d->window) {
QQuickWindowPrivate::get(d->window)->parentlessItems.remove(this);
}
@@ -2768,8 +2768,9 @@
d->itemChange(ItemParentHasChanged, d->parentItem);
- emit parentChanged(d->parentItem);
- if (isVisible() && d->parentItem)
+ if (!d->inDestructor)
+ emit parentChanged(d->parentItem);
+ if (isVisible() && d->parentItem && !QQuickItemPrivate::get(d->parentItem)->inDestructor)
emit d->parentItem->visibleChildrenChanged();
}
@@ -2965,7 +2966,8 @@
itemChange(QQuickItem::ItemChildRemovedChange, child);
- emit q->childrenChanged();
+ if (!inDestructor)
+ emit q->childrenChanged();
}
void QQuickItemPrivate::refWindow(QQuickWindow *c)
@@ -3194,6 +3196,7 @@
, touchEnabled(false)
#endif
, hasCursorHandler(false)
+ , inDestructor(false)
, dirtyAttributes(0)
, nextDirtyItem(nullptr)
, prevDirtyItem(nullptr)
@@ -6106,9 +6109,11 @@
QAccessible::updateAccessibility(&ev);
}
#endif
- emit q->visibleChanged();
- if (childVisibilityChanged)
- emit q->visibleChildrenChanged();
+ if (!inDestructor) {
+ emit q->visibleChanged();
+ if (childVisibilityChanged)
+ emit q->visibleChildrenChanged();
+ }
return true; // effective visibility DID change
}
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -472,6 +472,7 @@
bool replayingPressEvent:1;
bool touchEnabled:1;
bool hasCursorHandler:1;
+ quint32 inDestructor:1; // has entered ~QQuickItem
enum DirtyType {
TransformOrigin = 0x00000001,
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -130,6 +130,7 @@
void isAncestorOf();
void grab();
+ void signalsOnDestruction();
private:
QQmlEngine engine;
@@ -3520,6 +3521,52 @@
QVERIFY(!sub2.isAncestorOf(&sub2));
}
+/*
+ Items that are getting destroyed should not emit property change notifications.
+*/
+void tst_QQuickItem::signalsOnDestruction()
+{
+ QQuickWindow window;
+ window.show();
+
+ // visual children, but not QObject children
+ std::unique_ptr<QQuickItem> parent(new QQuickItem(window.contentItem()));
+ std::unique_ptr<QQuickItem> child(new QQuickItem);
+ std::unique_ptr<QQuickItem> grandChild(new QQuickItem);
+
+ QSignalSpy childrenSpy(parent.get(), &QQuickItem::childrenChanged);
+ QSignalSpy visibleChildrenSpy(parent.get(), &QQuickItem::visibleChildrenChanged);
+ QSignalSpy childParentSpy(child.get(), &QQuickItem::parentChanged);
+ QSignalSpy childChildrenSpy(child.get(), &QQuickItem::childrenChanged);
+ QSignalSpy childVisibleChildrenSpy(child.get(), &QQuickItem::visibleChanged);
+ QSignalSpy grandChildParentSpy(grandChild.get(), &QQuickItem::parentChanged);
+
+ child->setParentItem(parent.get());
+ QCOMPARE(childrenSpy.count(), 1);
+ QCOMPARE(visibleChildrenSpy.count(), 1);
+ QCOMPARE(childParentSpy.count(), 1);
+ QCOMPARE(childChildrenSpy.count(), 0);
+ QCOMPARE(childVisibleChildrenSpy.count(), 0);
+
+ grandChild->setParentItem(child.get());
+ QCOMPARE(childrenSpy.count(), 1);
+ QCOMPARE(visibleChildrenSpy.count(), 1);
+ QCOMPARE(childParentSpy.count(), 1);
+ QCOMPARE(childChildrenSpy.count(), 1);
+ QCOMPARE(childVisibleChildrenSpy.count(), 0);
+ QCOMPARE(grandChildParentSpy.count(), 1);
+
+ parent.reset();
+
+ QVERIFY(!child->parentItem());
+ QVERIFY(grandChild->parentItem());
+ QCOMPARE(childrenSpy.count(), 1);
+ QCOMPARE(visibleChildrenSpy.count(), 1);
+ QCOMPARE(childParentSpy.count(), 2);
+ QCOMPARE(grandChildParentSpy.count(), 1);
+}
+
+
QTEST_MAIN(tst_QQuickItem)
#include "tst_qquickitem.moc"
Reply to: