Fix infinite loop in dash stroker

When the positions were large enough, we would get precision errors
with the floating point numbers.

We calculate the relative position:
  dpos = pos + dashes[istart] - doffset - estart
and then later
  pos = dpos + estart

If estart is a huge number (range of 10^18) and dashes[istart] is
a low number (10^1), then estart + dashes[istart] == estart and
the loop will never progress, dpos will be 0.

Since the loop should never iterate more than dashCount times
(since we cut away all full dash sequences before entering it),
we add a failsafe that exits the loop if it detects the error.

Fixes: QTBUG-99690
Change-Id: Ia6a42f21b6b4c6adf5cdd703b6483750513a88ba
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
(cherry picked from commit 26a0638222933fc549f250333c28d0184205b704)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2022-02-03 11:01:33 +01:00 committed by Qt Cherry-pick Bot
parent b885c608a8
commit 7374e9760b

View File

@ -1184,6 +1184,7 @@ void QDashStroker::processCurrentSubpath()
// Check if the entire line should be clipped away or simplified // Check if the entire line should be clipped away or simplified
bool clipIt = clipping && !lineIntersectsRect(prev, e, clip_tl, clip_br); bool clipIt = clipping && !lineIntersectsRect(prev, e, clip_tl, clip_br);
bool skipDashing = elen * invSumLength > repetitionLimit(); bool skipDashing = elen * invSumLength > repetitionLimit();
int maxDashes = dashCount;
if (skipDashing || clipIt) { if (skipDashing || clipIt) {
// Cut away full dash sequences. // Cut away full dash sequences.
elen -= std::floor(elen * invSumLength) * sumLength; elen -= std::floor(elen * invSumLength) * sumLength;
@ -1198,7 +1199,7 @@ void QDashStroker::processCurrentSubpath()
pos = estop; // move pos to next path element pos = estop; // move pos to next path element
done = true; done = true;
} else { // Dash is on this line } else { // Dash is on this line
pos = dpos + estart; pos = --maxDashes > 0 ? dpos + estart : estop;
done = pos >= estop; done = pos >= estop;
if (++idash >= dashCount) if (++idash >= dashCount)
idash = 0; idash = 0;