summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2017-11-14 14:47:08 +0100
committerEirik Aavitsland <eirik.aavitsland@qt.io>2017-11-22 11:25:52 +0000
commit1167507b6422cd74a95cf0deffaccada9345dc27 (patch)
tree5da7583a17f8af5d2699bbd29ab12f0e0022fe2b
parent5bed32c8f5cabcbe22cabfc50a290f832dce6aec (diff)
Fix crash on recursive self-referral in <use> element
Referring to an ancestor in a <use> element would lead to endless recursion. Add checks to avoid recursion, and also emit a warning while parsing. Task-number: QTBUG-64425 Change-Id: I9ee1b9bfef13796cc3f387ff8579c6b13bc4ae9a Reviewed-by: Andy Shaw <andy.shaw@qt.io> (cherry picked from commit 18a2adad907523ea31251ff0b62e3321241a40fa)
-rw-r--r--src/svg/qsvggraphics.cpp5
-rw-r--r--src/svg/qsvghandler.cpp2
-rw-r--r--src/svg/qsvgnode.cpp11
-rw-r--r--src/svg/qsvgnode_p.h1
-rw-r--r--tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp15
5 files changed, 32 insertions, 2 deletions
diff --git a/src/svg/qsvggraphics.cpp b/src/svg/qsvggraphics.cpp
index e297a76..592592d 100644
--- a/src/svg/qsvggraphics.cpp
+++ b/src/svg/qsvggraphics.cpp
@@ -460,6 +460,9 @@ QSvgUse::QSvgUse(const QPointF &start, QSvgNode *parent, QSvgNode *node)
void QSvgUse::draw(QPainter *p, QSvgExtraStates &states)
{
+ if (Q_UNLIKELY(!m_link || isDescendantOf(m_link)))
+ return;
+
applyStyle(p, states);
if (!m_start.isNull()) {
@@ -548,7 +551,7 @@ QSvgNode::Type QSvgVideo::type() const
QRectF QSvgUse::bounds(QPainter *p, QSvgExtraStates &states) const
{
QRectF bounds;
- if (m_link) {
+ if (Q_LIKELY(m_link && !isDescendantOf(m_link))) {
p->translate(m_start);
bounds = m_link->transformedBounds(p, states);
p->translate(-m_start);
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index d373a99..036b870 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -3308,6 +3308,8 @@ static QSvgNode *createUseNode(QSvgNode *parent,
if (group) {
QSvgNode *link = group->scopeNode(linkId);
if (link) {
+ if (parent->isDescendantOf(link))
+ qWarning("link #%s is recursive!", qPrintable(linkId));
QPointF pt;
if (!xStr.isNull() || !yStr.isNull()) {
QSvgHandler::LengthType type;
diff --git a/src/svg/qsvgnode.cpp b/src/svg/qsvgnode.cpp
index 54548e0..0be621d 100644
--- a/src/svg/qsvgnode.cpp
+++ b/src/svg/qsvgnode.cpp
@@ -51,6 +51,17 @@ QSvgNode::~QSvgNode()
}
+bool QSvgNode::isDescendantOf(const QSvgNode *parent) const
+{
+ const QSvgNode *n = this;
+ while (n) {
+ if (n == parent)
+ return true;
+ n = n->m_parent;
+ }
+ return false;
+}
+
void QSvgNode::appendStyleProperty(QSvgStyleProperty *prop, const QString &id)
{
//qDebug()<<"appending "<<prop->type()<< " ("<< id <<") "<<"to "<<this<<this->type();
diff --git a/src/svg/qsvgnode_p.h b/src/svg/qsvgnode_p.h
index 4ba0e91..432e8c6 100644
--- a/src/svg/qsvgnode_p.h
+++ b/src/svg/qsvgnode_p.h
@@ -107,6 +107,7 @@ public:
virtual void draw(QPainter *p, QSvgExtraStates &states) =0;
QSvgNode *parent() const;
+ bool isDescendantOf(const QSvgNode *parent) const;
void appendStyleProperty(QSvgStyleProperty *prop, const QString &id);
void applyStyle(QPainter *p, QSvgExtraStates &states) const;
diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
index d35ff68..c272ef7 100644
--- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
+++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp
@@ -1313,6 +1313,17 @@ void tst_QSvgRenderer::testUseElement()
" <g fill = \"red\" fill-opacity =\"0.5\">"
" <use xlink:href =\"#usedG\" />"
" </g>"
+ "</svg>",
+ // Self referral, should be ignored
+ "<svg><g id=\"0\"><use xlink:href=\"#0\" /></g></svg>",
+ "<svg width=\"200\" height=\"200\">"
+ " <rect width=\"100\" height=\"50\"/>"
+ "</svg>",
+ "<svg width=\"200\" height=\"200\">"
+ " <g id=\"0\"><use xlink:href=\"#0\" /><rect width=\"100\" height=\"50\"/></g>"
+ "</svg>",
+ "<svg width=\"200\" height=\"200\">"
+ " <g id=\"0\"><g><use xlink:href=\"#0\" /><rect width=\"100\" height=\"50\"/></g></g>"
"</svg>"
};
@@ -1339,8 +1350,10 @@ void tst_QSvgRenderer::testUseElement()
// For this reason an exact comparison will fail.
QCOMPARE(images[4], images[i]);
}
- } else if (i > 7) {
+ } else if (i > 7 && i < 10) {
QCOMPARE(images[8], images[i]);
+ } else if (i > 11) {
+ QCOMPARE(images[11], images[i]);
}
}
}