diff options
author | caryclark <caryclark@google.com> | 2016-06-08 04:28:19 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-06-08 04:28:19 -0700 |
commit | dae6b97705fde08958b1a36fa6ce685d28fc692c (patch) | |
tree | 39b7c096c331a0a29a43ddc7455705f821f5f640 | |
parent | 2af4599b5c514933bf997d4837ddaaf24fc61cd7 (diff) |
fix pathops fuzz bugs
Fail out in a couple of new places when the input data is very
large and exceeds the limits of the pathops machinery.
Most of the change here plumbs in a way to exclude an assert in
one of these exceptional cases. The current SkAddIntersection
implementation and the inner functions it calls has no way to
report an error to the root caller for an early exit, so rather
than add that in, exclude the assert when the test that would
trigger it runs (allowing the test to otherwise ensure that it
properly fails).
TBR=reed@google.com
BUG=617586,617635
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2046713003
Review-Url: https://codereview.chromium.org/2046713003
-rw-r--r-- | src/pathops/SkAddIntersections.cpp | 2 | ||||
-rw-r--r-- | src/pathops/SkDConicLineIntersection.cpp | 11 | ||||
-rw-r--r-- | src/pathops/SkIntersections.h | 8 | ||||
-rw-r--r-- | src/pathops/SkOpBuilder.cpp | 19 | ||||
-rwxr-xr-x | src/pathops/SkOpCoincidence.cpp | 3 | ||||
-rw-r--r-- | src/pathops/SkPathOpsCommon.cpp | 3 | ||||
-rw-r--r-- | src/pathops/SkPathOpsCommon.h | 5 | ||||
-rw-r--r-- | src/pathops/SkPathOpsOp.cpp | 7 | ||||
-rw-r--r-- | src/pathops/SkPathOpsSimplify.cpp | 3 | ||||
-rw-r--r-- | src/pathops/SkPathOpsTightBounds.cpp | 3 | ||||
-rw-r--r-- | src/pathops/SkPathOpsTypes.cpp | 4 | ||||
-rw-r--r-- | src/pathops/SkPathOpsTypes.h | 3 | ||||
-rwxr-xr-x | tests/PathOpsAngleIdeas.cpp | 2 | ||||
-rw-r--r-- | tests/PathOpsAngleTest.cpp | 4 | ||||
-rw-r--r-- | tests/PathOpsBuilderTest.cpp | 22 | ||||
-rw-r--r-- | tests/PathOpsExtendedTest.cpp | 19 | ||||
-rw-r--r-- | tests/PathOpsExtendedTest.h | 2 | ||||
-rw-r--r-- | tests/PathOpsOpTest.cpp | 50 |
18 files changed, 141 insertions, 29 deletions
diff --git a/src/pathops/SkAddIntersections.cpp b/src/pathops/SkAddIntersections.cpp index 43d29d93e0..07666e796d 100644 --- a/src/pathops/SkAddIntersections.cpp +++ b/src/pathops/SkAddIntersections.cpp @@ -280,7 +280,7 @@ bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc continue; } int pts = 0; - SkIntersections ts; + SkIntersections ts { SkDEBUGCODE(test->globalState()) }; bool swap = false; SkDQuad quad1, quad2; SkDConic conic1, conic2; diff --git a/src/pathops/SkDConicLineIntersection.cpp b/src/pathops/SkDConicLineIntersection.cpp index e6d775f76e..2d906072fa 100644 --- a/src/pathops/SkDConicLineIntersection.cpp +++ b/src/pathops/SkDConicLineIntersection.cpp @@ -103,9 +103,14 @@ public: for (int index = 0; index < roots; ++index) { double conicT = rootVals[index]; double lineT = this->findLineT(conicT); - SkDEBUGCODE(SkDPoint conicPt = fConic.ptAtT(conicT)); - SkDEBUGCODE(SkDPoint linePt = fLine->ptAtT(lineT)); - SkASSERT(conicPt.approximatelyEqual(linePt)); +#ifdef SK_DEBUG + if (!fIntersections->debugGlobalState() + || !fIntersections->debugGlobalState()->debugSkipAssert()) { + SkDEBUGCODE(SkDPoint conicPt = fConic.ptAtT(conicT)); + SkDEBUGCODE(SkDPoint linePt = fLine->ptAtT(lineT)); + SkASSERT(conicPt.approximatelyEqual(linePt)); + } +#endif SkDPoint pt; if (this->pinTs(&conicT, &lineT, &pt, kPointUninitialized) && this->uniqueAnswer(conicT, pt)) { diff --git a/src/pathops/SkIntersections.h b/src/pathops/SkIntersections.h index b733ed0ea7..474142b269 100644 --- a/src/pathops/SkIntersections.h +++ b/src/pathops/SkIntersections.h @@ -15,9 +15,10 @@ class SkIntersections { public: - SkIntersections() + SkIntersections(SkDEBUGCODE(SkOpGlobalState* globalState = nullptr)) : fSwap(0) #ifdef SK_DEBUG + SkDEBUGPARAMS(fDebugGlobalState(globalState)) , fDepth(0) #endif { @@ -102,6 +103,10 @@ public: return intersect(cubic, line); } +#ifdef SK_DEBUG + SkOpGlobalState* debugGlobalState() { return fDebugGlobalState; } +#endif + bool hasT(double t) const { SkASSERT(t == 0 || t == 1); return fUsed > 0 && (t == 0 ? fT[0][0] == 0 : fT[0][fUsed - 1] == 1); @@ -309,6 +314,7 @@ private: bool fAllowNear; bool fSwap; #ifdef SK_DEBUG + SkOpGlobalState* fDebugGlobalState; int fDepth; #endif #if DEBUG_T_SECT_LOOP_COUNT diff --git a/src/pathops/SkOpBuilder.cpp b/src/pathops/SkOpBuilder.cpp index 4f53dee056..67aa92fe26 100644 --- a/src/pathops/SkOpBuilder.cpp +++ b/src/pathops/SkOpBuilder.cpp @@ -25,7 +25,7 @@ static bool one_contour(const SkPath& path) { return true; } -void FixWinding(SkPath* path) { +bool FixWinding(SkPath* path) { SkPath::FillType fillType = path->getFillType(); if (fillType == SkPath::kInverseEvenOdd_FillType) { fillType = SkPath::kInverseWinding_FillType; @@ -40,14 +40,17 @@ void FixWinding(SkPath* path) { *path = temp; } path->setFillType(fillType); - return; + return true; } SkChunkAlloc allocator(4096); SkOpContourHead contourHead; - SkOpGlobalState globalState(nullptr, &contourHead SkDEBUGPARAMS(nullptr)); + SkOpGlobalState globalState(nullptr, &contourHead SkDEBUGPARAMS(false) + SkDEBUGPARAMS(nullptr)); SkOpEdgeBuilder builder(*path, &contourHead, &allocator, &globalState); builder.finish(&allocator); - SkASSERT(contourHead.next()); + if (!contourHead.next()) { + return false; + } contourHead.resetReverse(); bool writePath = false; SkOpSpan* topSpan; @@ -69,7 +72,7 @@ void FixWinding(SkPath* path) { } if (!writePath) { path->setFillType(fillType); - return; + return true; } SkPath empty; SkPathWriter woundPath(empty); @@ -83,6 +86,7 @@ void FixWinding(SkPath* path) { } while ((test = test->next())); *path = *woundPath.nativePath(); path->setFillType(fillType); + return true; } void SkOpBuilder::add(const SkPath& path, SkPathOp op) { @@ -160,7 +164,10 @@ bool SkOpBuilder::resolve(SkPath* result) { } if (!fPathRefs[index].isEmpty()) { // convert the even odd result back to winding form before accumulating it - FixWinding(&fPathRefs[index]); + if (!FixWinding(&fPathRefs[index])) { + *result = original; + return false; + } sum.addPath(fPathRefs[index]); } } diff --git a/src/pathops/SkOpCoincidence.cpp b/src/pathops/SkOpCoincidence.cpp index 130d1daff7..42ee5c6091 100755 --- a/src/pathops/SkOpCoincidence.cpp +++ b/src/pathops/SkOpCoincidence.cpp @@ -90,6 +90,9 @@ bool SkOpCoincidence::addExpanded(SkChunkAlloc* allocator } SkOpSpanBase* test = start->upCast()->next(); SkOpSpanBase* oTest = coin->fFlipped ? oStart->prev() : oStart->upCast()->next(); + if (!oTest) { + return false; + } while (test != end || oTest != oEnd) { if (!test->ptT()->contains(oTest->ptT())) { // use t ranges to guess which one is missing diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp index c9ef7a4196..340b306d60 100644 --- a/src/pathops/SkPathOpsCommon.cpp +++ b/src/pathops/SkPathOpsCommon.cpp @@ -198,7 +198,8 @@ public: void Assemble(const SkPathWriter& path, SkPathWriter* simple) { SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune SkOpContourHead contour; - SkOpGlobalState globalState(nullptr, &contour SkDEBUGPARAMS(nullptr)); + SkOpGlobalState globalState(nullptr, &contour SkDEBUGPARAMS(false) + SkDEBUGPARAMS(nullptr)); #if DEBUG_SHOW_TEST_NAME SkDebugf("</div>\n"); #endif diff --git a/src/pathops/SkPathOpsCommon.h b/src/pathops/SkPathOpsCommon.h index 73bc0f42cc..856a984ce5 100644 --- a/src/pathops/SkPathOpsCommon.h +++ b/src/pathops/SkPathOpsCommon.h @@ -22,11 +22,12 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr, SkOpSpan* FindSortableTop(SkOpContourHead* ); SkOpSegment* FindUndone(SkOpContourHead* , SkOpSpanBase** startPtr, SkOpSpanBase** endPtr); -void FixWinding(SkPath* path); +bool FixWinding(SkPath* path); bool SortContourList(SkOpContourHead** , bool evenOdd, bool oppEvenOdd); bool HandleCoincidence(SkOpContourHead* , SkOpCoincidence* , SkChunkAlloc* ); bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result, - bool expectSuccess SkDEBUGPARAMS(const char* testName)); + bool expectSuccess SkDEBUGPARAMS(bool skipAssert) + SkDEBUGPARAMS(const char* testName)); #if DEBUG_ACTIVE_SPANS void DebugShowActiveSpans(SkOpContourHead* ); #endif diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp index 257cb8ee69..b71ca9e481 100644 --- a/src/pathops/SkPathOpsOp.cpp +++ b/src/pathops/SkPathOpsOp.cpp @@ -246,12 +246,13 @@ extern void (*gVerboseFinalize)(); #endif bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result, - bool expectSuccess SkDEBUGPARAMS(const char* testName)) { + bool expectSuccess SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)) { SkChunkAlloc allocator(4096); // FIXME: add a constant expression here, tune SkOpContour contour; SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); SkOpCoincidence coincidence; - SkOpGlobalState globalState(&coincidence, contourList SkDEBUGPARAMS(testName)); + SkOpGlobalState globalState(&coincidence, contourList + SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName)); #if DEBUGGING_PATHOPS_FROM_HOST dump_op(one, two, op); #endif @@ -454,6 +455,6 @@ bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { } return true; #else - return OpDebug(one, two, op, result, true SkDEBUGPARAMS(nullptr)); + return OpDebug(one, two, op, result, true SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)); #endif } diff --git a/src/pathops/SkPathOpsSimplify.cpp b/src/pathops/SkPathOpsSimplify.cpp index 97f0350db2..fa1003054e 100644 --- a/src/pathops/SkPathOpsSimplify.cpp +++ b/src/pathops/SkPathOpsSimplify.cpp @@ -180,7 +180,8 @@ bool Simplify(const SkPath& path, SkPath* result) { SkOpCoincidence coincidence; SkOpContour contour; SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); - SkOpGlobalState globalState(&coincidence, contourList SkDEBUGPARAMS(nullptr)); + SkOpGlobalState globalState(&coincidence, contourList SkDEBUGPARAMS(false) + SkDEBUGPARAMS(nullptr)); #if DEBUG_SORT SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; #endif diff --git a/src/pathops/SkPathOpsTightBounds.cpp b/src/pathops/SkPathOpsTightBounds.cpp index ac5d6aae0b..19593c228b 100644 --- a/src/pathops/SkPathOpsTightBounds.cpp +++ b/src/pathops/SkPathOpsTightBounds.cpp @@ -11,7 +11,8 @@ bool TightBounds(const SkPath& path, SkRect* result) { SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune SkOpContour contour; SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); - SkOpGlobalState globalState(nullptr, contourList SkDEBUGPARAMS(nullptr)); + SkOpGlobalState globalState(nullptr, contourList SkDEBUGPARAMS(false) + SkDEBUGPARAMS(nullptr)); // turn path into list of segments SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); if (!builder.finish(&allocator)) { diff --git a/src/pathops/SkPathOpsTypes.cpp b/src/pathops/SkPathOpsTypes.cpp index 1ed484afee..bad1bc7a8b 100644 --- a/src/pathops/SkPathOpsTypes.cpp +++ b/src/pathops/SkPathOpsTypes.cpp @@ -213,6 +213,7 @@ double SkDCubeRoot(double x) { } SkOpGlobalState::SkOpGlobalState(SkOpCoincidence* coincidence, SkOpContourHead* head + SkDEBUGPARAMS(bool debugSkipAssert) SkDEBUGPARAMS(const char* testName)) : fCoincidence(coincidence) , fContourHead(head) @@ -226,7 +227,8 @@ SkOpGlobalState::SkOpGlobalState(SkOpCoincidence* coincidence, SkOpContourHead* SkDEBUGPARAMS(fContourID(0)) SkDEBUGPARAMS(fPtTID(0)) SkDEBUGPARAMS(fSegmentID(0)) - SkDEBUGPARAMS(fSpanID(0)) { + SkDEBUGPARAMS(fSpanID(0)) + SkDEBUGPARAMS(fDebugSkipAssert(debugSkipAssert)) { if (coincidence) { coincidence->debugSetGlobalState(this); } diff --git a/src/pathops/SkPathOpsTypes.h b/src/pathops/SkPathOpsTypes.h index b35c97ef06..00c3e5fe93 100644 --- a/src/pathops/SkPathOpsTypes.h +++ b/src/pathops/SkPathOpsTypes.h @@ -31,6 +31,7 @@ class SkIntersectionHelper; class SkOpGlobalState { public: SkOpGlobalState(SkOpCoincidence* coincidence, SkOpContourHead* head + SkDEBUGPARAMS(bool debugSkipAssert) SkDEBUGPARAMS(const char* testName)); enum Phase { @@ -69,6 +70,7 @@ public: const class SkOpPtT* debugPtT(int id) const; bool debugRunFail() const; const class SkOpSegment* debugSegment(int id) const; + bool debugSkipAssert() const { return fDebugSkipAssert; } const class SkOpSpanBase* debugSpan(int id) const; const char* debugTestName() const { return fDebugTestName; } #endif @@ -152,6 +154,7 @@ private: int fPtTID; int fSegmentID; int fSpanID; + bool fDebugSkipAssert; #endif #if DEBUG_T_SECT_LOOP_COUNT int fDebugLoopCount[3]; diff --git a/tests/PathOpsAngleIdeas.cpp b/tests/PathOpsAngleIdeas.cpp index 8fc100ee02..2e3c7b9066 100755 --- a/tests/PathOpsAngleIdeas.cpp +++ b/tests/PathOpsAngleIdeas.cpp @@ -419,7 +419,7 @@ static void testQuadAngles(skiatest::Reporter* reporter, const SkDQuad& quad1, c SkPoint shortQuads[2][3]; SkOpContourHead contour; - SkOpGlobalState state(nullptr, &contour SkDEBUGPARAMS(nullptr)); + SkOpGlobalState state(nullptr, &contour SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)); contour.init(&state, false, false); makeSegment(&contour, quad1, shortQuads[0], allocator); makeSegment(&contour, quad1, shortQuads[1], allocator); diff --git a/tests/PathOpsAngleTest.cpp b/tests/PathOpsAngleTest.cpp index faf5da50f2..6389c305bb 100644 --- a/tests/PathOpsAngleTest.cpp +++ b/tests/PathOpsAngleTest.cpp @@ -235,7 +235,7 @@ static const int circleDataSetSize = (int) SK_ARRAY_COUNT(circleDataSet); DEF_TEST(PathOpsAngleCircle, reporter) { SkChunkAlloc allocator(4096); SkOpContourHead contour; - SkOpGlobalState state(nullptr, &contour SkDEBUGPARAMS(nullptr)); + SkOpGlobalState state(nullptr, &contour SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)); contour.init(&state, false, false); for (int index = 0; index < circleDataSetSize; ++index) { CircleData& data = circleDataSet[index]; @@ -427,7 +427,7 @@ struct FourPoints { DEF_TEST(PathOpsAngleAfter, reporter) { SkChunkAlloc allocator(4096); SkOpContourHead contour; - SkOpGlobalState state(nullptr, &contour SkDEBUGPARAMS(nullptr)); + SkOpGlobalState state(nullptr, &contour SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)); contour.init(&state, false, false); for (int index = intersectDataSetsSize - 1; index >= 0; --index) { IntersectData* dataArray = intersectDataSets[index]; diff --git a/tests/PathOpsBuilderTest.cpp b/tests/PathOpsBuilderTest.cpp index e191ecee5e..e29b4bc473 100644 --- a/tests/PathOpsBuilderTest.cpp +++ b/tests/PathOpsBuilderTest.cpp @@ -301,3 +301,25 @@ DEF_TEST(Issue569540, reporter) { SkPath result; builder.resolve(&result); } + +DEF_TEST(SkOpBuilderFuzz665, reporter) { + SkPath path; + path.setFillType(SkPath::kEvenOdd_FillType); +path.moveTo(SkBits2Float(0xcc4264a7), SkBits2Float(0x4bb12e50)); // -5.0959e+07f, 2.32235e+07f +path.lineTo(SkBits2Float(0xcc4264b0), SkBits2Float(0x4bb12e48)); // -5.0959e+07f, 2.32234e+07f +path.lineTo(SkBits2Float(0xcc4264a7), SkBits2Float(0x4bb12e50)); // -5.0959e+07f, 2.32235e+07f +path.close(); + SkPath path1(path); + path.reset(); + path.setFillType(SkPath::kWinding_FillType); +path.moveTo(SkBits2Float(0x43213333), SkBits2Float(0x43080000)); // 161.2f, 136 +path.lineTo(SkBits2Float(0x43038000), SkBits2Float(0x43080000)); // 131.5f, 136 +path.cubicTo(SkBits2Float(0x43038000), SkBits2Float(0x42f00000), SkBits2Float(0x42f16666), SkBits2Float(0x42d53333), SkBits2Float(0x42d3cccd), SkBits2Float(0x42cd6666)); // 131.5f, 120, 120.7f, 106.6f, 105.9f, 102.7f +path.lineTo(SkBits2Float(0x42e33333), SkBits2Float(0x42940000)); // 113.6f, 74 + SkPath path2(path); + SkOpBuilder builder; + builder.add(path1, kUnion_SkPathOp); + builder.add(path2, kUnion_SkPathOp); + SkPath result; + builder.resolve(&result); +} diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp index b5bf5b8d9f..572766086a 100644 --- a/tests/PathOpsExtendedTest.cpp +++ b/tests/PathOpsExtendedTest.cpp @@ -488,15 +488,17 @@ static void showName(const SkPath& a, const SkPath& b, const SkPathOp shapeOp) { #endif bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result, - bool expectSuccess SkDEBUGPARAMS(const char* testName)); + bool expectSuccess SkDEBUGPARAMS(bool skipAssert) + SkDEBUGPARAMS(const char* testName)); static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, - const SkPathOp shapeOp, const char* testName, bool expectSuccess) { + const SkPathOp shapeOp, const char* testName, bool expectSuccess, bool skipAssert) { #if 0 && DEBUG_SHOW_TEST_NAME showName(a, b, shapeOp); #endif SkPath out; - if (!OpDebug(a, b, shapeOp, &out, expectSuccess SkDEBUGPARAMS(testName))) { + if (!OpDebug(a, b, shapeOp, &out, expectSuccess SkDEBUGPARAMS(skipAssert) + SkDEBUGPARAMS(testName))) { SkDebugf("%s did not expect failure\n", __FUNCTION__); REPORTER_ASSERT(reporter, 0); return false; @@ -536,17 +538,22 @@ static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkP bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const char* testName) { - return innerPathOp(reporter, a, b, shapeOp, testName, true); + return innerPathOp(reporter, a, b, shapeOp, testName, true, false); } bool testPathOpCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const char* testName, bool checkFail) { - return innerPathOp(reporter, a, b, shapeOp, testName, checkFail); + return innerPathOp(reporter, a, b, shapeOp, testName, checkFail, false); } bool testPathOpFailCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const char* testName) { - return innerPathOp(reporter, a, b, shapeOp, testName, false); + return innerPathOp(reporter, a, b, shapeOp, testName, false, false); +} + +bool testPathSkipAssertOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, + const SkPathOp shapeOp, const char* testName) { + return innerPathOp(reporter, a, b, shapeOp, testName, true, true); } bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, diff --git a/tests/PathOpsExtendedTest.h b/tests/PathOpsExtendedTest.h index 17073833cb..0a6f4ab91f 100644 --- a/tests/PathOpsExtendedTest.h +++ b/tests/PathOpsExtendedTest.h @@ -44,6 +44,8 @@ extern bool testPathOpFailCheck(skiatest::Reporter* reporter, const SkPath& a, c const SkPathOp , const char* testName); extern bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, const SkPathOp , const char* testName); +extern bool testPathSkipAssertOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, + const SkPathOp , const char* testName); extern bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state, const char* pathStr); extern bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename); diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp index 00a8f52477..d75c9a6fb6 100644 --- a/tests/PathOpsOpTest.cpp +++ b/tests/PathOpsOpTest.cpp @@ -5836,7 +5836,57 @@ SkPath path2(path); testPathFailOp(reporter, path1, path2, (SkPathOp) 1, filename); } +static void fuzz1450_0(skiatest::Reporter* reporter, const char* filename) { +SkPath path; +path.moveTo(SkBits2Float(0x43b40000), SkBits2Float(0xcf000000)); // 360, -2.14748e+09f +path.conicTo(SkBits2Float(0x4e800002), SkBits2Float(0xcf000000), SkBits2Float(0x4e800002), SkBits2Float(0xce7ffffe), SkBits2Float(0x3f3504f4)); // 1.07374e+09f, -2.14748e+09f, 1.07374e+09f, -1.07374e+09f, 0.707107f +path.conicTo(SkBits2Float(0x4e800002), SkBits2Float(0x43800001), SkBits2Float(0x43348000), SkBits2Float(0x43800001), SkBits2Float(0x3f3504f4)); // 1.07374e+09f, 256, 180.5f, 256, 0.707107f +SkPath path1(path); +path.reset(); +path.moveTo(SkBits2Float(0x43b40000), SkBits2Float(0x45816000)); // 360, 4140 +path.conicTo(SkBits2Float(0x43b40005), SkBits2Float(0x458a945d), SkBits2Float(0x45610000), SkBits2Float(0x458a945d), SkBits2Float(0x3f3504f3)); // 360, 4434.55f, 3600, 4434.55f, 0.707107f +path.conicTo(SkBits2Float(0x45d5bfff), SkBits2Float(0x458a945d), SkBits2Float(0x45d5bfff), SkBits2Float(0x45816000), SkBits2Float(0x3f3504f3)); // 6840, 4434.55f, 6840, 4140, 0.707107f +path.lineTo(SkBits2Float(0x42c80000), SkBits2Float(0x44000000)); // 100, 512 +path.lineTo(SkBits2Float(0x42000000), SkBits2Float(0x41800000)); // 32, 16 +path.lineTo(SkBits2Float(0x43b40000), SkBits2Float(0x44800000)); // 360, 1024 +path.lineTo(SkBits2Float(0x43b40000), SkBits2Float(0x45816000)); // 360, 4140 +path.close(); +SkPath path2(path); +testPathSkipAssertOp(reporter, path1, path2, kUnion_SkPathOp, filename); +} + +static void fuzz1450_1(skiatest::Reporter* reporter, const char* filename) { +SkPath path; +path.setFillType(SkPath::kEvenOdd_FillType); +path.moveTo(SkBits2Float(0x4e800002), SkBits2Float(0xce7ffffe)); // 1.07374e+09f, -1.07374e+09f +path.conicTo(SkBits2Float(0x4e800002), SkBits2Float(0xcf000000), SkBits2Float(0x43b40000), SkBits2Float(0xcf000000), SkBits2Float(0x3f3504f4)); // 1.07374e+09f, -2.14748e+09f, 360, -2.14748e+09f, 0.707107f +path.lineTo(SkBits2Float(0x43348000), SkBits2Float(0x43800001)); // 180.5f, 256 +path.lineTo(SkBits2Float(0x42000000), SkBits2Float(0x41800000)); // 32, 16 +path.lineTo(SkBits2Float(0x42c80000), SkBits2Float(0x44000000)); // 100, 512 +path.lineTo(SkBits2Float(0x43553abd), SkBits2Float(0x440f3cbd)); // 213.229f, 572.949f +path.lineTo(SkBits2Float(0x43b40000), SkBits2Float(0x44800000)); // 360, 1024 +path.lineTo(SkBits2Float(0x43b40000), SkBits2Float(0x45816000)); // 360, 4140 +path.conicTo(SkBits2Float(0x43b40005), SkBits2Float(0x458a945d), SkBits2Float(0x45610000), SkBits2Float(0x458a945d), SkBits2Float(0x3f3504f3)); // 360, 4434.55f, 3600, 4434.55f, 0.707107f +path.conicTo(SkBits2Float(0x45d5bfff), SkBits2Float(0x458a945d), SkBits2Float(0x45d5bfff), SkBits2Float(0x45816000), SkBits2Float(0x3f3504f3)); // 6840, 4434.55f, 6840, 4140, 0.707107f +path.lineTo(SkBits2Float(0x43553abd), SkBits2Float(0x440f3cbd)); // 213.229f, 572.949f +path.lineTo(SkBits2Float(0x43348000), SkBits2Float(0x43800001)); // 180.5f, 256 +path.conicTo(SkBits2Float(0x4e800002), SkBits2Float(0x43800001), SkBits2Float(0x4e800002), SkBits2Float(0xce7ffffe), SkBits2Float(0x3f3504f4)); // 1.07374e+09f, 256, 1.07374e+09f, -1.07374e+09f, 0.707107f +path.close(); +SkPath path1(path); +path.reset(); +path.moveTo(SkBits2Float(0x42fe0000), SkBits2Float(0x43a08000)); // 127, 321 +path.lineTo(SkBits2Float(0x45d5c000), SkBits2Float(0x43870000)); // 6840, 270 +path.lineTo(SkBits2Float(0xd0a00000), SkBits2Float(0x4cbebc20)); // -2.14748e+10f, 1e+08 +path.lineTo(SkBits2Float(0x451f7000), SkBits2Float(0x42800000)); // 2551, 64 +path.lineTo(SkBits2Float(0x42fe0000), SkBits2Float(0x43a08000)); // 127, 321 +path.close(); +SkPath path2(path); +testPathFailOp(reporter, path1, path2, kUnion_SkPathOp, filename); +} + static struct TestDesc failTests[] = { + TEST(fuzz1450_1), + TEST(fuzz1450_0), TEST(bug597926_0), TEST(fuzz535151), TEST(fuzz753_91), |