diff options
author | Hatem ElKharashy <hatem.elkharashy@qt.io> | 2024-01-04 14:32:08 +0200 |
---|---|---|
committer | Hatem ElKharashy <hatem.elkharashy@qt.io> | 2024-01-08 15:00:16 +0200 |
commit | 69bed6cd3f12a3c1b0182c5a3706efa617090cfa (patch) | |
tree | e75eeb44c767466263baf453efbcc59f9a9596c6 | |
parent | 7b3da9aa0421369f84e7a1ea32df350821440d4b (diff) |
QRadialGradient: Fix undefined behavior
The UBSan raises a division by zero in getRadialGradientValues. This can
be avoided by calculating the inverse in
qt_fetch_radial_gradient_template as a checker is done to avoid
division by zero there. (Credit to OSS-Fuzz)
Pick-to: 6.7
Fixes: QTBUG-120332
Change-Id: I798d1efc87ee07df7ca6f401aa476013cdbffe42
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
-rw-r--r-- | src/gui/painting/qdrawhelper.cpp | 1 | ||||
-rw-r--r-- | src/gui/painting/qdrawhelper_p.h | 9 | ||||
-rw-r--r-- | tests/auto/gui/painting/qpainter/tst_qpainter.cpp | 16 |
3 files changed, 20 insertions, 6 deletions
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 7029a0e0a3..5fe0a5b41b 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -3413,7 +3413,6 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius; v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy; - v->inv2a = 1 / (2 * v->a); v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0; } diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 5f58d55dd0..833ddd7b16 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -174,7 +174,6 @@ struct RadialGradientValues qreal dr; qreal sqrfr; qreal a; - qreal inv2a; bool extended; }; @@ -402,12 +401,12 @@ const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffe bool affine = !data->m13 && !data->m23; BlendType *end = buffer + length; + qreal inv_a = 1 / qreal(2 * op->radial.a); + if (affine) { rx -= data->gradient.radial.focal.x; ry -= data->gradient.radial.focal.y; - qreal inv_a = 1 / qreal(2 * op->radial.a); - const qreal delta_rx = data->m11; const qreal delta_ry = data->m12; @@ -452,8 +451,8 @@ const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffe if (det >= 0) { qreal detSqrt = qSqrt(det); - qreal s0 = (-b - detSqrt) * op->radial.inv2a; - qreal s1 = (-b + detSqrt) * op->radial.inv2a; + qreal s0 = (-b - detSqrt) * inv_a; + qreal s1 = (-b + detSqrt) * inv_a; qreal s = qMax(s0, s1); diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp index a8981f5761..553044dd3d 100644 --- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -169,6 +169,7 @@ private slots: void radialGradientRgb30(); #endif + void radialGradient_QTBUG120332_ubsan(); void fpe_pixmapTransform(); void fpe_zeroLengthLines(); void fpe_divByZero(); @@ -3896,6 +3897,21 @@ void tst_QPainter::gradientPixelFormat() QCOMPARE(a, b.convertToFormat(QImage::Format_ARGB32_Premultiplied)); } +void tst_QPainter::radialGradient_QTBUG120332_ubsan() +{ + // Check if Radial Gradient will cause division by zero or not when + // the center point coincide with the focal point. + QImage image(8, 8, QImage::Format_ARGB32_Premultiplied); + QPainter painter(&image); + + QPointF center(0.5, 0.5); + QPointF focal(0.5, 0.5); + QRadialGradient gradient(center, 0.5, focal, 0.5); + gradient.setColorAt(0, Qt::blue); + gradient.setColorAt(1, Qt::red); + painter.fillRect(image.rect(), QBrush(gradient)); +} + void tst_QPainter::gradientInterpolation() { QImage image(256, 8, QImage::Format_ARGB32_Premultiplied); |