From dc53698ba4476194d0f8b2971eeb132169563962 Mon Sep 17 00:00:00 2001 From: Hatem ElKharashy Date: Wed, 22 Apr 2026 13:46:59 +0300 Subject: [PATCH] Fix rendering causing stack overflow With a deeply nested svg document, the process will run out of stack if the stack is limited. To fix this, a limit to the number of nested element is used to stop rendering if the current nested level is exceeding the max limit. Task-number: QTBUG-145916 Change-Id: I2047aa3d64332b47a7c2819bcc3219eabbc00891 Reviewed-by: Robert Löhning (cherry picked from commit 16119ddc0f8a39a7131d95715c7d9c01e428819d) (cherry picked from commit b898d5b01c2b1576e6cbe577e2215f59992ef57a) --- diff --git a/src/svg/qsvgnode.cpp b/src/svg/qsvgnode.cpp index 37a22df..1df78c4 100644 --- a/src/svg/qsvgnode.cpp +++ b/src/svg/qsvgnode.cpp @@ -42,6 +42,16 @@ #endif if (shouldDrawNode(p, states)) { + quint8 remainingDepth = states.trustedSource ? states.remainingNestedNodes + : states.remainingNestedNodes - 1; + QScopedValueRollback nestedNodesGuard(states.remainingNestedNodes, remainingDepth); + if (states.remainingNestedNodes == 0) { + qCWarning(lcSvgDraw) << "Too many nested nodes at" << qPrintable(typeName()) + << "exceeding max nested limit of" << QtSvg::renderingMaxNestedNodes << "." + << "Enable AssumeTrustedSource in QSvgHandler or set QT_SVG_DEFAULT_OPTIONS=2 to disable this check."; + return; + } + applyStyle(p, states); QSvgNode *maskNode = this->hasMask() ? document()->namedNode(this->maskId()) : nullptr; QSvgFilterContainer *filterNode = this->hasFilter() ? static_cast(document()->namedNode(this->filterId())) @@ -673,7 +683,7 @@ if (m_displayMode == DisplayMode::NoneMode) return false; - if (document() && document()->options().testFlag(QtSvg::AssumeTrustedSource)) + if (document() && states.trustedSource) return true; QRectF brect = internalFastBounds(p, states); diff --git a/src/svg/qsvgstyle_p.h b/src/svg/qsvgstyle_p.h index e2c56da..4afaa06 100644 --- a/src/svg/qsvgstyle_p.h +++ b/src/svg/qsvgstyle_p.h @@ -117,6 +117,8 @@ qreal strokeDashOffset; int nestedUseLevel = 0; int nestedUseCount = 0; + bool trustedSource = false; + quint8 remainingNestedNodes = QtSvg::renderingMaxNestedNodes; bool vectorEffect; // true if pen is cosmetic qint8 imageRendering; // QSvgQualityStyle::ImageRendering bool inUse = false; // true if currently in QSvgUseNode diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index c63e7e1..29bf184 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -33,6 +33,7 @@ , m_fps(30) , m_options(options) { + m_states.trustedSource = m_options.testFlag(QtSvg::AssumeTrustedSource); } QSvgTinyDocument::~QSvgTinyDocument() diff --git a/src/svg/qtsvgglobal_p.h b/src/svg/qtsvgglobal_p.h index 28c3b3f..30cd723 100644 --- a/src/svg/qtsvgglobal_p.h +++ b/src/svg/qtsvgglobal_p.h @@ -28,6 +28,7 @@ userSpaceOnUse }; +constexpr quint8 renderingMaxNestedNodes = 32; } QT_END_NAMESPACE