diff options
-rw-r--r-- | src/effects/SkDashPathEffect.cpp | 16 | ||||
-rw-r--r-- | tests/DrawPathTest.cpp | 21 |
2 files changed, 37 insertions, 0 deletions
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp index 10ef81b5d1..4f442fd1c5 100644 --- a/src/effects/SkDashPathEffect.cpp +++ b/src/effects/SkDashPathEffect.cpp @@ -164,6 +164,7 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, 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 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, 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 fdabd0198d..e8cfa54d36 100644 --- a/tests/DrawPathTest.cpp +++ b/tests/DrawPathTest.cpp @@ -241,6 +241,26 @@ static void test_infinite_dash(skiatest::Reporter* reporter) { 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 @@ static void TestDrawPath(skiatest::Reporter* reporter) { test_inversepathwithclip(reporter); // test_crbug131181(reporter); test_infinite_dash(reporter); + test_crbug_165432(reporter); } #include "TestClassDef.h" |