Skip to content

Commit

Permalink
Do stricter error checking when parsing path nodes
Browse files Browse the repository at this point in the history
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 36cfd9e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
  • Loading branch information
aavit authored and Qt Cherry-pick Bot committed Oct 27, 2021
1 parent 6a809aa commit a3b753c
Showing 1 changed file with 25 additions and 34 deletions.
59 changes: 25 additions & 34 deletions src/svg/qsvghandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1611,14 +1611,16 @@ 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;
QPointF ctrlPt;
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;
Expand All @@ -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;
Expand All @@ -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];
Expand All @@ -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;
Expand All @@ -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];
Expand Down Expand Up @@ -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);
Expand All @@ -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]);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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]);
Expand All @@ -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);
Expand All @@ -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]);
Expand All @@ -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++);
Expand All @@ -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++);
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit a3b753c

Please sign in to comment.