Handle overflow of accumulated rect perimeter in SkDaskPath cull_path
The fuzzer test case was:
-15,-11 ------> huge,-11
^ |
| v
-15,5000 <------ huge,5000
where the 'huge' x-value caused the accumulated perimeter to overflow.
Bug:1175370, skia:11307
Change-Id: Ic6760d38c29c440d2d4fcb225a5c556e56a992f6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/368317
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/src/utils/SkDashPath.cpp b/src/utils/SkDashPath.cpp
index f8612f4..64a6db6 100644
--- a/src/utils/SkDashPath.cpp
+++ b/src/utils/SkDashPath.cpp
@@ -191,12 +191,13 @@
SkPoint pts[4]; // Rects are all moveTo and lineTo, so we'll only use pts[0] and pts[1].
SkAssertResult(SkPath::kMove_Verb == iter.next(pts));
- SkScalar accum = 0; // Sum of unculled edge lengths to keep the phase correct.
+ double accum = 0; // Sum of unculled edge lengths to keep the phase correct.
+ // Intentionally a double to minimize the risk of overflow and drift.
while (iter.next(pts) == SkPath::kLine_Verb) {
// Notice this vector v and accum work with the original unclipped length.
SkVector v = pts[1] - pts[0];
- if (clip_line(pts, bounds, intervalLength, SkScalarMod(accum, intervalLength))) {
+ if (clip_line(pts, bounds, intervalLength, std::fmod(accum, intervalLength))) {
// pts[0] may have just been changed by clip_line().
// If that's not where we ended the previous lineTo(), we need to moveTo() there.
SkPoint last;