summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArno Rehn <a.rehn@menlosystems.com>2020-08-10 21:52:14 +0200
committerDaniel Smith <Daniel.Smith@qt.io>2020-08-24 12:09:35 +0000
commit62f2be9de24bd3760f507e3ceda5b5a1a7f3dbec (patch)
treeaedb85a1c678256b7592b1d247343e7c493340ce
parente1487e8192ca287f29f0f20c616aba972872b7ae (diff)
downloadqtwebchannel-62f2be9de24bd3760f507e3ceda5b5a1a7f3dbec.tar.gz
Fix infinite recursion when wrapping a self-contained object twice
The previous unit test for self-contained objects only wrapped the test object once. After wrapping, a different code path is taken which still exhibited infinite recursion. This patch addresses both the unit test and the infinite recursion. To fix the problem, a boolean in the ObjectInfo struct is toggled to indicate whether the object in question is currently being wrapped. If that is the case, the recursing code path is skipped. [ChangeLog][General] Fixed infinite recursion when dealing with self contained objects. Fixes: QTBUG-84007 Change-Id: Ie0898fb5f28cec91587897835ff937672d60f2a1 Reviewed-by: Kai Koehne <kai.koehne@qt.io> (adapted from commit 0451ef836415c93a6beb68a315a25c6ab27f44fa) Reviewed-by: Paul Wicking <paul.wicking@qt.io>
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp21
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h4
-rw-r--r--tests/auto/webchannel/tst_webchannel.cpp3
3 files changed, 20 insertions, 8 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index 677f79c..536eb5c 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -754,14 +754,21 @@ QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelA
wrappedObjects.insert(id, oi);
initializePropertyUpdates(object, classInfo);
- } else if (wrappedObjects.contains(id)) {
- Q_ASSERT(object == wrappedObjects.value(id).object);
- // check if this transport is already assigned to the object
- if (transport && !wrappedObjects.value(id).transports.contains(transport)) {
- wrappedObjects[id].transports.append(transport);
- transportedWrappedObjects.insert(transport, id);
+ } else {
+ auto oi = wrappedObjects.find(id);
+ if (oi != wrappedObjects.end() && !oi->isBeingWrapped) {
+ Q_ASSERT(object == oi->object);
+ // check if this transport is already assigned to the object
+ if (transport && !oi->transports.contains(transport)) {
+ oi->transports.append(transport);
+ transportedWrappedObjects.insert(transport, id);
+ }
+ // QTBUG-84007: Block infinite recursion for self-contained objects
+ // which have already been wrapped
+ oi->isBeingWrapped = true;
+ classInfo = classInfoForObject(object, transport);
+ oi->isBeingWrapped = false;
}
- classInfo = classInfoForObject(object, transport);
}
QJsonObject objectInfo;
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
index 6030de2..bbd9875 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -292,13 +292,15 @@ private:
QHash<const QObject *, QString> registeredObjectIds;
// Groups individually wrapped objects with their class information and the transports that have access to it.
+ // Also tags objects that are in the process of being wrapped to prevent infinite recursion.
struct ObjectInfo
{
ObjectInfo(QObject *o = nullptr)
- : object(o)
+ : object(o), isBeingWrapped(false)
{}
QObject *object;
QVector<QWebChannelAbstractTransport*> transports;
+ bool isBeingWrapped;
};
// Map of objects wrapped from invocation returns
diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp
index a1e824b..181da9e 100644
--- a/tests/auto/webchannel/tst_webchannel.cpp
+++ b/tests/auto/webchannel/tst_webchannel.cpp
@@ -936,6 +936,9 @@ void TestWebChannel::testInfiniteRecursion()
channel.d_func()->publisher->initializeClient(m_dummyTransport);
QJsonObject objectInfo = channel.d_func()->publisher->wrapResult(QVariant::fromValue(&obj), m_dummyTransport).toObject();
+
+ // Wrap the result twice to test for QTBUG-84007. A single result wrap will not trigger all recursion paths.
+ objectInfo = channel.d_func()->publisher->wrapResult(QVariant::fromValue(&obj), m_dummyTransport).toObject();
}
void TestWebChannel::testAsyncObject()