diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2019-05-02 14:45:35 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2019-06-07 10:43:16 +0200 |
commit | d73497cf770c92e38903850267fd8737df3578ca (patch) | |
tree | bd8523d20d750bd3461e959df0e4865137ac914a /src/widgets/kernel | |
parent | 9dec965248503836ad478b1c1ffdd7f34aed048b (diff) |
QObject/QWidget::setParent: add assertions to prevent loops
It is perfectly possible to accidentally create a parent/child
loop. This can happens by direct means (a->setParent(b);
b->setParent(a);), or some more subtle means, e.g.
class MyClass : public QObject {
MyClass() : QObject(this) {}
};
Since this is UB, add a few robustness checks to make sure the
code above crashes right away (at least in debug builds).
Change-Id: I6583c8514b4c1f8a90677b04c77b8e8f0c15dba3
Reviewed-by: Liang Qi <liang.qi@qt.io>
Reviewed-by: Sérgio Martins <sergio.martins@kdab.com>
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 8f927e8bee..58963d5eec 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -79,6 +79,7 @@ #include "private/qstylesheetstyle_p.h" #include "private/qstyle_p.h" #include "qfileinfo.h" +#include "qscopeguard.h" #include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/qinputmethod.h> #include <QtGui/qopenglcontext.h> @@ -1123,6 +1124,8 @@ void QWidgetPrivate::adjustFlags(Qt::WindowFlags &flags, QWidget *w) void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) { Q_Q(QWidget); + Q_ASSERT_X(q != parentWidget, Q_FUNC_INFO, "Cannot parent a QWidget to itself"); + if (Q_UNLIKELY(!qobject_cast<QApplication *>(QCoreApplication::instance()))) qFatal("QWidget: Cannot create a QWidget without QApplication"); @@ -10677,6 +10680,22 @@ static void sendWindowChangeToTextureChildrenRecursively(QWidget *widget) void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) { Q_D(QWidget); + Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QWidget to itself"); +#ifdef QT_DEBUG + const auto checkForParentChildLoops = qScopeGuard([&](){ + int depth = 0; + auto p = parentWidget(); + while (p) { + if (++depth == QObjectPrivate::CheckForParentChildLoopsWarnDepth) { + qWarning("QWidget %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; " + "this is undefined behavior", + this, metaObject()->className(), qPrintable(objectName())); + } + p = p->parentWidget(); + } + }); +#endif + bool resized = testAttribute(Qt::WA_Resized); bool wasCreated = testAttribute(Qt::WA_WState_Created); QWidget *oldtlw = window(); |