Blame SOURCES/qtbase-CVE-2021-38593.patch

5a92eb
From 081d835c040a90f8ee76807354355062ac521dfb Mon Sep 17 00:00:00 2001
5a92eb
From: Eirik Aavitsland <eirik.aavitsland@qt.io>
5a92eb
Date: Tue, 13 Apr 2021 14:23:45 +0200
5a92eb
Subject: [PATCH] Avoid processing-intensive painting of high number of tiny
5a92eb
 dashes
5a92eb
5a92eb
When stroking a dashed path, an unnecessary amount of processing would
5a92eb
be spent if there is a huge number of dashes visible, e.g. because of
5a92eb
scaling. Since the dashes are too small to be indivdually visible
5a92eb
anyway, just replace with a semi-transparent solid line for such
5a92eb
cases.
5a92eb
5a92eb
Pick-to: 6.1 6.0 5.15
5a92eb
Change-Id: I9e9f7861257ad5bce46a0cf113d1a9d7824911e6
5a92eb
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
5a92eb
(cherry picked from commit f4d791b330d02777fcaf02938732892eb3167e9b)
5a92eb
5a92eb
* asturmlechner 2021-08-21:
5a92eb
Conflict from preceding 94dd2ceb in dev branch:
5a92eb
	src/gui/painting/qpaintengineex.cpp
5a92eb
	Resolved via:
5a92eb
5a92eb
     if (pen.style() > Qt::SolidLine) {
5a92eb
         QRectF cpRect = path.controlPointRect();
5a92eb
         const QTransform &xf = state()->matrix;
5a92eb
-        if (pen.isCosmetic()) {
5a92eb
+        if (qt_pen_is_cosmetic(pen, state()->renderHints)){
5a92eb
             clipRect = d->exDeviceRect;
5a92eb
             cpRect.translate(xf.dx(), xf.dy());
5a92eb
         } else {
5a92eb
5a92eb
FTBFS from preceding 471e4fcb in dev branch changing QVector to QList:
5a92eb
	Resolved via:
5a92eb
5a92eb
         QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
5a92eb
         qreal extent = qMax(extentRect.width(), extentRect.height());
5a92eb
         qreal patternLength = 0;
5a92eb
-        const QList<qreal> pattern = pen.dashPattern();
5a92eb
+        const QVector<qreal> pattern = pen.dashPattern();
5a92eb
         const int patternSize = qMin(pattern.size(), 32);
5a92eb
         for (int i = 0; i < patternSize; i++)
5a92eb
             patternLength += qMax(pattern.at(i), qreal(0));
5a92eb
---
5a92eb
 src/gui/painting/qpaintengineex.cpp           | 44 +++++++++++++++----
5a92eb
 .../other/lancelot/scripts/tinydashes.qps     | 34 ++++++++++++++
5a92eb
 2 files changed, 69 insertions(+), 9 deletions(-)
5a92eb
 create mode 100644 tests/auto/other/lancelot/scripts/tinydashes.qps
5a92eb
5a92eb
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
5a92eb
index 5d8f89eadd..55fdb0c2a0 100644
5a92eb
--- a/src/gui/painting/qpaintengineex.cpp
5a92eb
+++ b/src/gui/painting/qpaintengineex.cpp
5a92eb
@@ -385,7 +385,7 @@ QPainterState *QPaintEngineEx::createState(QPainterState *orig) const
5a92eb
5a92eb
 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
5a92eb
5a92eb
-void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
5a92eb
+void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
5a92eb
 {
5a92eb
 #ifdef QT_DEBUG_DRAW
5a92eb
     qDebug() << "QPaintEngineEx::stroke()" << pen;
5a92eb
@@ -403,6 +403,38 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
5a92eb
         d->stroker.setCubicToHook(qpaintengineex_cubicTo);
5a92eb
     }
5a92eb
5a92eb
+    QRectF clipRect;
5a92eb
+    QPen pen = inPen;
5a92eb
+    if (pen.style() > Qt::SolidLine) {
5a92eb
+        QRectF cpRect = path.controlPointRect();
5a92eb
+        const QTransform &xf = state()->matrix;
5a92eb
+        if (qt_pen_is_cosmetic(pen, state()->renderHints)){
5a92eb
+            clipRect = d->exDeviceRect;
5a92eb
+            cpRect.translate(xf.dx(), xf.dy());
5a92eb
+        } else {
5a92eb
+            clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
5a92eb
+        }
5a92eb
+        // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
5a92eb
+        QRectF extentRect = cpRect & clipRect;
5a92eb
+        qreal extent = qMax(extentRect.width(), extentRect.height());
5a92eb
+        qreal patternLength = 0;
5a92eb
+        const QVector<qreal> pattern = pen.dashPattern();
5a92eb
+        const int patternSize = qMin(pattern.size(), 32);
5a92eb
+        for (int i = 0; i < patternSize; i++)
5a92eb
+            patternLength += qMax(pattern.at(i), qreal(0));
5a92eb
+        if (pen.widthF())
5a92eb
+            patternLength *= pen.widthF();
5a92eb
+        if (qFuzzyIsNull(patternLength)) {
5a92eb
+            pen.setStyle(Qt::NoPen);
5a92eb
+        } else if (extent / patternLength > 10000) {
5a92eb
+            // approximate stream of tiny dashes with semi-transparent solid line
5a92eb
+            pen.setStyle(Qt::SolidLine);
5a92eb
+            QColor color(pen.color());
5a92eb
+            color.setAlpha(color.alpha() / 2);
5a92eb
+            pen.setColor(color);
5a92eb
+        }
5a92eb
+    }
5a92eb
+
5a92eb
     if (!qpen_fast_equals(pen, d->strokerPen)) {
5a92eb
         d->strokerPen = pen;
5a92eb
         d->stroker.setJoinStyle(pen.joinStyle());
5a92eb
@@ -430,14 +462,8 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
5a92eb
         return;
5a92eb
     }
5a92eb
5a92eb
-    if (pen.style() > Qt::SolidLine) {
5a92eb
-        if (qt_pen_is_cosmetic(pen, state()->renderHints)){
5a92eb
-            d->activeStroker->setClipRect(d->exDeviceRect);
5a92eb
-        } else {
5a92eb
-            QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect));
5a92eb
-            d->activeStroker->setClipRect(clipRect);
5a92eb
-        }
5a92eb
-    }
5a92eb
+    if (!clipRect.isNull())
5a92eb
+        d->activeStroker->setClipRect(clipRect);
5a92eb
5a92eb
     if (d->activeStroker == &d->stroker)
5a92eb
         d->stroker.setForceOpen(path.hasExplicitOpen());
5a92eb
diff --git a/tests/auto/other/lancelot/scripts/tinydashes.qps b/tests/auto/other/lancelot/scripts/tinydashes.qps
5a92eb
new file mode 100644
5a92eb
index 0000000000..d41ced7f5f
5a92eb
--- /dev/null
5a92eb
+++ b/tests/auto/other/lancelot/scripts/tinydashes.qps
5a92eb
@@ -0,0 +1,34 @@
5a92eb
+# Version: 1
5a92eb
+# CheckVsReference: 5%
5a92eb
+
5a92eb
+path_addEllipse mypath 20.0 20.0 200.0 200.0
5a92eb
+
5a92eb
+save
5a92eb
+setPen blue 20 SolidLine FlatCap
5a92eb
+pen_setCosmetic true
5a92eb
+pen_setDashPattern [ 0.0004 0.0004 ]
5a92eb
+setBrush yellow
5a92eb
+
5a92eb
+drawPath mypath
5a92eb
+translate 300 0
5a92eb
+setRenderHint Antialiasing true
5a92eb
+drawPath mypath
5a92eb
+restore
5a92eb
+
5a92eb
+path_addEllipse bigpath 200000.0 200000.0 2000000.0 2000000.0
5a92eb
+
5a92eb
+setPen blue 20 DotLine FlatCap
5a92eb
+setBrush yellow
5a92eb
+
5a92eb
+save
5a92eb
+translate 0 300
5a92eb
+scale 0.0001 0.00011
5a92eb
+drawPath bigpath
5a92eb
+restore
5a92eb
+
5a92eb
+save
5a92eb
+translate 300 300
5a92eb
+setRenderHint Antialiasing true
5a92eb
+scale 0.0001 0.00011
5a92eb
+drawPath bigpath
5a92eb
+restore
5a92eb
--
5a92eb
GitLab
5a92eb
5a92eb
From 6b400e3147dcfd8cc3a393ace1bd118c93762e0c Mon Sep 17 00:00:00 2001
5a92eb
From: Eirik Aavitsland <eirik.aavitsland@qt.io>
5a92eb
Date: Fri, 23 Jul 2021 15:53:56 +0200
5a92eb
Subject: [PATCH] Improve fix for avoiding huge number of tiny dashes
5a92eb
MIME-Version: 1.0
5a92eb
Content-Type: text/plain; charset=UTF-8
5a92eb
Content-Transfer-Encoding: 8bit
5a92eb
5a92eb
Some pathological cases were not caught by the previous fix.
5a92eb
5a92eb
Fixes: QTBUG-95239
5a92eb
Pick-to: 6.2 6.1 5.15
5a92eb
Change-Id: I0337ee3923ff93ccb36c4d7b810a9c0667354cc5
5a92eb
Reviewed-by: Robert Löhning <robert.loehning@qt.io>
5a92eb
---
5a92eb
 src/gui/painting/qpaintengineex.cpp | 2 +-
5a92eb
 1 file changed, 1 insertion(+), 1 deletion(-)
5a92eb
5a92eb
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
5a92eb
index 2997d533107..22e9a621c3c 100644
5a92eb
--- a/src/gui/painting/qpaintengineex.cpp
5a92eb
+++ b/src/gui/painting/qpaintengineex.cpp
5a92eb
@@ -426,7 +426,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
5a92eb
             patternLength *= pen.widthF();
5a92eb
         if (qFuzzyIsNull(patternLength)) {
5a92eb
             pen.setStyle(Qt::NoPen);
5a92eb
-        } else if (extent / patternLength > 10000) {
5a92eb
+        } else if (qFuzzyIsNull(extent) || extent / patternLength > 10000) {
5a92eb
             // approximate stream of tiny dashes with semi-transparent solid line
5a92eb
             pen.setStyle(Qt::SolidLine);
5a92eb
             QColor color(pen.color());
5a92eb
5a92eb
From 427df34efdcb56582a9ae9f7d2d1f39eeff70328 Mon Sep 17 00:00:00 2001
5a92eb
From: Eirik Aavitsland <eirik.aavitsland@qt.io>
5a92eb
Date: Fri, 30 Jul 2021 13:03:49 +0200
5a92eb
Subject: [PATCH] Refix for avoiding huge number of tiny dashes
5a92eb
5a92eb
Previous fix hit too widely so some valid horizontal and vertical
5a92eb
lines were affected; the root problem being that such lines have an
5a92eb
empty control point rect (width or height is 0). Fix by caculating in
5a92eb
the pen width.
5a92eb
5a92eb
Pick-to: 6.2 6.1 5.15
5a92eb
Change-Id: I7a436e873f6d485028f6759d0e2c6456f07eebdc
5a92eb
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
5a92eb
(cherry picked from commit 84aba80944a2e1c3058d7a1372e0e66676411884)
5a92eb
---
5a92eb
 src/gui/painting/qpaintengineex.cpp           |  8 ++---
5a92eb
 .../gui/painting/qpainter/tst_qpainter.cpp    | 31 +++++++++++++++++++
5a92eb
 2 files changed, 35 insertions(+), 4 deletions(-)
5a92eb
5a92eb
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
5a92eb
index 19e4b23423..9fe510827a 100644
5a92eb
--- a/src/gui/painting/qpaintengineex.cpp
5a92eb
+++ b/src/gui/painting/qpaintengineex.cpp
5a92eb
@@ -415,18 +415,18 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
5a92eb
             clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
5a92eb
         }
5a92eb
         // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
5a92eb
-        QRectF extentRect = cpRect & clipRect;
5a92eb
+        qreal pw = pen.widthF() ? pen.widthF() : 1;
5a92eb
+        QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
5a92eb
         qreal extent = qMax(extentRect.width(), extentRect.height());
5a92eb
         qreal patternLength = 0;
5a92eb
         const QVector<qreal> pattern = pen.dashPattern();
5a92eb
         const int patternSize = qMin(pattern.size(), 32);
5a92eb
         for (int i = 0; i < patternSize; i++)
5a92eb
             patternLength += qMax(pattern.at(i), qreal(0));
5a92eb
-        if (pen.widthF())
5a92eb
-            patternLength *= pen.widthF();
5a92eb
+        patternLength *= pw;
5a92eb
         if (qFuzzyIsNull(patternLength)) {
5a92eb
             pen.setStyle(Qt::NoPen);
5a92eb
-        } else if (qFuzzyIsNull(extent) || extent / patternLength > 10000) {
5a92eb
+        } else if (extent / patternLength > 10000) {
5a92eb
             // approximate stream of tiny dashes with semi-transparent solid line
5a92eb
             pen.setStyle(Qt::SolidLine);
5a92eb
             QColor color(pen.color());
5a92eb
diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
5a92eb
index 42e98ce363..d7c3f95f1d 100644
5a92eb
--- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
5a92eb
+++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
5a92eb
@@ -308,6 +308,7 @@ private slots:
5a92eb
     void fillPolygon();
5a92eb
5a92eb
     void drawImageAtPointF();
5a92eb
+    void scaledDashes();
5a92eb
5a92eb
 private:
5a92eb
     void fillData();
5a92eb
@@ -5468,6 +5469,36 @@ void tst_QPainter::drawImageAtPointF()
5a92eb
     paint.end();
5a92eb
 }
5a92eb
5a92eb
+void tst_QPainter::scaledDashes()
5a92eb
+{
5a92eb
+    // Test that we do not hit the limit-huge-number-of-dashes path
5a92eb
+    QRgb fore = qRgb(0, 0, 0xff);
5a92eb
+    QRgb back = qRgb(0xff, 0xff, 0);
5a92eb
+    QImage image(5, 32, QImage::Format_RGB32);
5a92eb
+    image.fill(back);
5a92eb
+    QPainter p(&image);
5a92eb
+    QPen pen(QColor(fore), 3, Qt::DotLine);
5a92eb
+    p.setPen(pen);
5a92eb
+    p.scale(1, 2);
5a92eb
+    p.drawLine(2, 0, 2, 16);
5a92eb
+    p.end();
5a92eb
+
5a92eb
+    bool foreFound = false;
5a92eb
+    bool backFound = false;
5a92eb
+    int i = 0;
5a92eb
+    while (i < 32 && (!foreFound || !backFound)) {
5a92eb
+        QRgb pix = image.pixel(3, i);
5a92eb
+        if (pix == fore)
5a92eb
+            foreFound = true;
5a92eb
+        else if (pix == back)
5a92eb
+            backFound = true;
5a92eb
+        i++;
5a92eb
+    }
5a92eb
+
5a92eb
+    QVERIFY(foreFound);
5a92eb
+    QVERIFY(backFound);
5a92eb
+}
5a92eb
+
5a92eb
 QTEST_MAIN(tst_QPainter)
5a92eb
5a92eb
 #include "tst_qpainter.moc"
5a92eb
--
5a92eb
GitLab