summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2021-10-25 14:17:55 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-10-27 09:40:10 +0000
commita3b753c2d077313fc9eb93af547051b956e383fc (patch)
treeed6ada1e050af5713a69b927659d1a7e4e23e0f1
parent6a809aaacd161e99026da137b6a35adc4e321e61 (diff)
downloadqtsvg-a3b753c2d077313fc9eb93af547051b956e383fc.tar.gz
Do stricter error checking when parsing path nodes
The SVG spec mandates that path parsing should terminate on the first error encountered, and an error be reported. To improve the handling of corrupt files, implement such error handling, and also limit the number of QPainterPath elements to a reasonable range. Fixes: QTBUG-96044 Change-Id: Ic5e65d6b658516d6f1317c72de365c8c7ad81891 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io> Reviewed-by: Robert Löhning <robert.loehning@qt.io> (cherry picked from commit 36cfd9efb9b22b891adee9c48d30202289cfa620) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/svg/qsvghandler.cpp59
1 files changed, 25 insertions, 34 deletions
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index 08ee781..db21d5f 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -1611,6 +1611,7 @@ static void pathArc(QPainterPath &path,
static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
{
+ const int maxElementCount = 0x7fff; // Assume file corruption if more path elements than this
qreal x0 = 0, y0 = 0; // starting point
qreal x = 0, y = 0; // current point
char lastMode = 0;
@@ -1618,7 +1619,8 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
const QChar *str = dataStr.constData();
const QChar *end = str + dataStr.size();
- while (str != end) {
+ bool ok = true;
+ while (ok && str != end) {
while (str->isSpace() && (str + 1) != end)
++str;
QChar pathElem = *str;
@@ -1632,14 +1634,13 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
arg.append(0);//dummy
const qreal *num = arg.constData();
int count = arg.count();
- while (count > 0) {
+ while (ok && count > 0) {
qreal offsetX = x; // correction offsets
qreal offsetY = y; // for relative commands
switch (pathElem.unicode()) {
case 'm': {
if (count < 2) {
- num++;
- count--;
+ ok = false;
break;
}
x = x0 = num[0] + offsetX;
@@ -1656,8 +1657,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'M': {
if (count < 2) {
- num++;
- count--;
+ ok = false;
break;
}
x = x0 = num[0];
@@ -1683,8 +1683,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'l': {
if (count < 2) {
- num++;
- count--;
+ ok = false;
break;
}
x = num[0] + offsetX;
@@ -1697,8 +1696,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'L': {
if (count < 2) {
- num++;
- count--;
+ ok = false;
break;
}
x = num[0];
@@ -1738,8 +1736,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'c': {
if (count < 6) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c1(num[0] + offsetX, num[1] + offsetY);
@@ -1755,8 +1752,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'C': {
if (count < 6) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c1(num[0], num[1]);
@@ -1772,8 +1768,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 's': {
if (count < 4) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c1;
@@ -1794,8 +1789,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'S': {
if (count < 4) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c1;
@@ -1816,8 +1810,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'q': {
if (count < 4) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c(num[0] + offsetX, num[1] + offsetY);
@@ -1832,8 +1825,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'Q': {
if (count < 4) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF c(num[0], num[1]);
@@ -1848,8 +1840,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 't': {
if (count < 2) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF e(num[0] + offsetX, num[1] + offsetY);
@@ -1869,8 +1860,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'T': {
if (count < 2) {
- num += count;
- count = 0;
+ ok = false;
break;
}
QPointF e(num[0], num[1]);
@@ -1890,8 +1880,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
case 'a': {
if (count < 7) {
- num += count;
- count = 0;
+ ok = false;
break;
}
qreal rx = (*num++);
@@ -1913,8 +1902,7 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
break;
case 'A': {
if (count < 7) {
- num += count;
- count = 0;
+ ok = false;
break;
}
qreal rx = (*num++);
@@ -1935,12 +1923,15 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
}
break;
default:
- return false;
+ ok = false;
+ break;
}
lastMode = pathElem.toLatin1();
+ if (path.elementCount() > maxElementCount)
+ ok = false;
}
}
- return true;
+ return ok;
}
static bool parseStyle(QSvgNode *node,
@@ -2976,8 +2967,8 @@ static QSvgNode *createPathNode(QSvgNode *parent,
QPainterPath qpath;
qpath.setFillRule(Qt::WindingFill);
- //XXX do error handling
- parsePathDataFast(data, qpath);
+ if (!parsePathDataFast(data, qpath))
+ qCWarning(lcSvgHandler, "Invalid path data; path truncated.");
QSvgNode *path = new QSvgPath(parent, qpath);
return path;