fix dashimpl underflow

Previous impl would assert (and read past legal memory) for the new test.

Bug: skia: 8274
Bug: 875494
Change-Id: I2a2e20085d54d611151a9e20ae9cebf33c511329
Reviewed-on: https://skia-review.googlesource.com/148940
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/src/utils/SkDashPath.cpp b/src/utils/SkDashPath.cpp
index fc73c9f..454a8b5 100644
--- a/src/utils/SkDashPath.cpp
+++ b/src/utils/SkDashPath.cpp
@@ -361,6 +361,8 @@
                                 int32_t count, SkScalar initialDashLength, int32_t initialDashIndex,
                                 SkScalar intervalLength,
                                 StrokeRecApplication strokeRecApplication) {
+    // we must always have an even number of intervals
+    SkASSERT(is_even(count));
 
     // we do nothing if the src wants to be filled
     SkStrokeRec::Style style = rec->getStyle();
@@ -384,6 +386,14 @@
             while (endPhase > intervals[index]) {
                 endPhase -= intervals[index++];
                 SkASSERT(index <= count);
+                if (index == count) {
+                    // We have run out of intervals. endPhase "should" never get to this point,
+                    // but it could if the subtracts underflowed. Hence we will pin it as if it
+                    // perfectly ran through the intervals.
+                    // See crbug.com/875494 (and skbug.com/8274)
+                    endPhase = 0;
+                    break;
+                }
             }
             // if dash ends inside "on", or ends at beginning of "off"
             if (is_even(index) == (endPhase > 0)) {
diff --git a/tests/DashPathEffectTest.cpp b/tests/DashPathEffectTest.cpp
index f165207..c50c88d 100644
--- a/tests/DashPathEffectTest.cpp
+++ b/tests/DashPathEffectTest.cpp
@@ -123,3 +123,20 @@
     p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
     canvas->drawLine(1, 1, 1, 5.0e10f, p);
 }
+
+// This used to cause SkDashImpl to walk off the end of the intervals array, due to underflow
+// trying to substract a smal value from a large one in floats.
+DEF_TEST(DashCrazy_crbug_875494, r) {
+    SkScalar vals[] = { 98, 94, 2888458849.f, 227, 0, 197 };
+    const int N = SK_ARRAY_COUNT(vals);
+
+    SkRect cull = SkRect::MakeXYWH(43,236,57,149);
+    SkPath path;
+    path.addRect(cull);
+
+    SkPath path2;
+    SkPaint paint;
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setPathEffect(SkDashPathEffect::Make(vals, N, 222));
+    paint.getFillPath(path, &path2, &cull);
+}