From 9ea1f0f8b98fb5a65261c611bdfdc71b05673268 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Sat, 25 Dec 2021 17:23:40 +0100 Subject: Fix qobject_cast on partially destroyed QWidget/QWindow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QWidget and QWindow use bits in QObjectPrivate to provide for a couple of shortcuts -- one in qobject_cast, and another in the isWidgetType() / isWindowType() functions in QObject. These can be optimized by simply looking at the bits, without actually doing more expensive runtime casts. These bits were set on construction, but not unset on destruction. The result was for instance that destroying a QWidget would report that the object was still a QWidget when ~QObject was reached. Fix this 1) by setting the bits only when QWidget / QWindow constructors start; 2) by resetting the bits once ~QWidget / ~QWindow are completed. Technically speaking this is not 100% correct in the presence of data members, but luckily those classes don't have any. Amend an existing test for QWidget (whose comment said exactly the opposite of what the test actually did) and add a test for QWindow. Some other code was wrongly relying on isWidgetType() returning true for destroyed QWidgets; amend it as needed. [ChangeLog][QtCore][QObject] Using qobject_cast on partially constructed or destroyed QWidget/QWindow instances now yields correct results. Similarly, using the convenience isWidgetType() / isWindowType() functions now correctly return false on such instances. Before, qobject_cast (and the convenience functions) would erroneously report that a given object was a QWidget (resp. QWindow) even during that object's construction (before QObject's constructor had completed) or destruction (after QWidget's (resp. QWindow's) destructors had been completed). This was semantically wrong and inconsistent with other ways of gathering runtime type information regarding such an object (e.g. dynamic_cast, obj->metaObject()->className() and so on). Pick-to: 6.3 Change-Id: Ic45a887951755a9d1a3b838590f1e9f2c4ae6e92 Reviewed-by: Qt CI Bot Reviewed-by: Marc Mutz Reviewed-by: Tor Arne Vestbø --- src/widgets/kernel/qlayout.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/widgets/kernel/qlayout.cpp') diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index 044176d141..2867bd9fb1 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -570,12 +570,14 @@ void QLayout::widgetEvent(QEvent *e) case QEvent::ChildRemoved: { QChildEvent *c = (QChildEvent *)e; - if (c->child()->isWidgetType()) { + QObject *child = c->child(); + QObjectPrivate *op = QObjectPrivate::get(child); + if (op->wasWidget) { #if QT_CONFIG(menubar) - if (c->child() == d->menubar) + if (child == d->menubar) d->menubar = nullptr; #endif - removeWidgetRecursively(this, c->child()); + removeWidgetRecursively(this, child); } } break; -- cgit v1.2.3