Limit the maximum number of dash segments per path

https://crbug.com/165432

In order to avoid trivial out-of-memory exploits, cap path dashing at 1000000 segments per path.

R=reed@google.com

BUG=

Review URL: https://codereview.appspot.com/6948063

git-svn-id: http://skia.googlecode.com/svn/trunk@6845 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp
index 10ef81b..4f442fd 100644
--- a/src/effects/SkDashPathEffect.cpp
+++ b/src/effects/SkDashPathEffect.cpp
@@ -164,6 +164,7 @@
 
     SkPathMeasure   meas(src, false);
     const SkScalar* intervals = fIntervals;
+    SkScalar        dashCount = 0;
 
     SpecialLineRec lineRec;
     const bool specialLine = lineRec.init(src, dst, rec, meas.getLength(),
@@ -176,6 +177,21 @@
         int         index = fInitialDashIndex;
         SkScalar    scale = SK_Scalar1;
 
+        // Since the path length / dash length ratio may be arbitrarily large, we can exert
+        // significant memory pressure while attempting to build the filtered path. To avoid this,
+        // we simply give up dashing beyond a certain threshold.
+        //
+        // The original bug report (http://crbug.com/165432) is based on a path yielding more than
+        // 90 million dash segments and crashing the memory allocator. A limit of 1 million
+        // segments seems reasonable: at 2 verbs per segment * 9 bytes per verb, this caps the
+        // maximum dash memory overhead at roughly 17MB per path.
+        static const SkScalar kMaxDashCount = 1000000;
+        dashCount += length * (fCount >> 1) / fIntervalLength;
+        if (dashCount > kMaxDashCount) {
+            dst->reset();
+            return false;
+        }
+
         if (fScaleToFit) {
             if (fIntervalLength >= length) {
                 scale = SkScalarDiv(length, fIntervalLength);
diff --git a/tests/DrawPathTest.cpp b/tests/DrawPathTest.cpp
index fdabd01..e8cfa54 100644
--- a/tests/DrawPathTest.cpp
+++ b/tests/DrawPathTest.cpp
@@ -241,6 +241,26 @@
     REPORTER_ASSERT(reporter, true);
 }
 
+// http://crbug.com/165432
+// Limit extreme dash path effects to avoid exhausting the system memory.
+static void test_crbug_165432(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.moveTo(0, 0);
+    path.lineTo(10000000, 0);
+
+    SkScalar intervals[] = { 0.5f, 0.5f };
+    SkDashPathEffect dash(intervals, 2, 0);
+
+    SkPaint paint;
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setPathEffect(&dash);
+
+    SkPath filteredPath;
+    SkStrokeRec rec(paint);
+    REPORTER_ASSERT(reporter, !dash.filterPath(&filteredPath, path, &rec));
+    REPORTER_ASSERT(reporter, filteredPath.isEmpty());
+}
+
 static void TestDrawPath(skiatest::Reporter* reporter) {
     test_giantaa(reporter);
     test_bug533(reporter);
@@ -251,6 +271,7 @@
     test_inversepathwithclip(reporter);
 //    test_crbug131181(reporter);
     test_infinite_dash(reporter);
+    test_crbug_165432(reporter);
 }
 
 #include "TestClassDef.h"