summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject.cpp
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2019-05-02 14:45:35 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2019-06-07 10:43:16 +0200
commitd73497cf770c92e38903850267fd8737df3578ca (patch)
treebd8523d20d750bd3461e959df0e4865137ac914a /src/corelib/kernel/qobject.cpp
parent9dec965248503836ad478b1c1ffdd7f34aed048b (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/corelib/kernel/qobject.cpp')
-rw-r--r--src/corelib/kernel/qobject.cpp22
1 files changed, 22 insertions, 0 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 965857d408..b4e7568a23 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -58,6 +58,7 @@
#include <qdebug.h>
#include <qpair.h>
#include <qvarlengtharray.h>
+#include <qscopeguard.h>
#include <qset.h>
#if QT_CONFIG(thread)
#include <qsemaphore.h>
@@ -851,6 +852,8 @@ static bool check_parent_thread(QObject *parent,
QObject::QObject(QObject *parent)
: d_ptr(new QObjectPrivate)
{
+ Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself");
+
Q_D(QObject);
d_ptr->q_ptr = this;
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
@@ -879,6 +882,8 @@ QObject::QObject(QObject *parent)
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
+ Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself");
+
Q_D(QObject);
d_ptr->q_ptr = this;
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
@@ -2069,8 +2074,25 @@ void QObjectPrivate::deleteChildren()
void QObjectPrivate::setParent_helper(QObject *o)
{
Q_Q(QObject);
+ Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
+#ifdef QT_DEBUG
+ const auto checkForParentChildLoops = qScopeGuard([&](){
+ int depth = 0;
+ auto p = parent;
+ while (p) {
+ if (++depth == CheckForParentChildLoopsWarnDepth) {
+ qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
+ "this is undefined behavior",
+ q, q->metaObject()->className(), qPrintable(q->objectName()));
+ }
+ p = p->parent();
+ }
+ });
+#endif
+
if (o == parent)
return;
+
if (parent) {
QObjectPrivate *parentD = parent->d_func();
if (parentD->isDeletingChildren && wasDeleted