From 3f0753d3eccece8ac7f02f6af36d66a96c3dfb26 Mon Sep 17 00:00:00 2001 From: caryclark Date: Tue, 28 Jun 2016 09:23:57 -0700 Subject: [PATCH] fix fuzz bugs Detect more places where the pathops numerics cause numbers to become nearly identical and subsequently fail. These tests have extreme inputs and cannot succeed. Also remove the expectSuccess parameter from PathOpsDebug and check instead in the test framework. R=mbarbella@chromium.org TBR=reed@google.com BUG=623072,623022 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2103513002 Review-Url: https://codereview.chromium.org/2103513002 --- src/pathops/SkDConicLineIntersection.cpp | 4 +- src/pathops/SkOpCoincidence.cpp | 35 +++++++++++++----- src/pathops/SkOpCoincidence.h | 6 +-- src/pathops/SkPathOpsCommon.cpp | 12 ++++-- src/pathops/SkPathOpsCommon.h | 4 +- src/pathops/SkPathOpsConic.cpp | 5 ++- src/pathops/SkPathOpsOp.cpp | 8 ++-- tests/PathOpsExtendedTest.cpp | 17 ++++++--- tests/PathOpsExtendedTest.h | 2 + tests/PathOpsOpTest.cpp | 63 ++++++++++++++++++++++++++++++++ 10 files changed, 128 insertions(+), 28 deletions(-) diff --git a/src/pathops/SkDConicLineIntersection.cpp b/src/pathops/SkDConicLineIntersection.cpp index 2d90607..7106472 100644 --- a/src/pathops/SkDConicLineIntersection.cpp +++ b/src/pathops/SkDConicLineIntersection.cpp @@ -157,7 +157,9 @@ public: double conicT = roots[index]; SkDPoint pt = fConic.ptAtT(conicT); SkDEBUGCODE_(double conicVals[] = { fConic[0].fX, fConic[1].fX, fConic[2].fX }); - SkASSERT(close_to(pt.fX, axisIntercept, conicVals)); + SkASSERT((fIntersections->debugGlobalState() && + fIntersections->debugGlobalState()->debugSkipAssert()) || + close_to(pt.fX, axisIntercept, conicVals)); double lineT = (pt.fY - top) / (bottom - top); if (this->pinTs(&conicT, &lineT, &pt, kPointInitialized) && this->uniqueAnswer(conicT, pt)) { diff --git a/src/pathops/SkOpCoincidence.cpp b/src/pathops/SkOpCoincidence.cpp index b72bd6c..4b46e68 100755 --- a/src/pathops/SkOpCoincidence.cpp +++ b/src/pathops/SkOpCoincidence.cpp @@ -326,34 +326,41 @@ bool SkOpCoincidence::addMissing(SkChunkAlloc* allocator) { return added; } -void SkOpCoincidence::addOverlap(SkOpSegment* seg1, SkOpSegment* seg1o, SkOpSegment* seg2, +bool SkOpCoincidence::addOverlap(SkOpSegment* seg1, SkOpSegment* seg1o, SkOpSegment* seg2, SkOpSegment* seg2o, SkOpPtT* overS, SkOpPtT* overE, SkChunkAlloc* allocator) { SkOpPtT* s1 = overS->find(seg1); SkOpPtT* e1 = overE->find(seg1); + if (approximately_equal_half(s1->fT, e1->fT)) { + return false; + } if (!s1->starter(e1)->span()->upCast()->windValue()) { s1 = overS->find(seg1o); e1 = overE->find(seg1o); if (!s1->starter(e1)->span()->upCast()->windValue()) { - return; + return true; } } SkOpPtT* s2 = overS->find(seg2); SkOpPtT* e2 = overE->find(seg2); + if (approximately_equal_half(s2->fT, e2->fT)) { + return false; + } if (!s2->starter(e2)->span()->upCast()->windValue()) { s2 = overS->find(seg2o); e2 = overE->find(seg2o); if (!s2->starter(e2)->span()->upCast()->windValue()) { - return; + return true; } } if (s1->segment() == s2->segment()) { - return; + return true; } if (s1->fT > e1->fT) { SkTSwap(s1, e1); SkTSwap(s2, e2); } this->add(s1, e1, s2, e2, allocator); + return true; } bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, @@ -540,7 +547,7 @@ bool SkOpCoincidence::expand() { return expanded; } -void SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps, SkChunkAlloc* allocator) const { +bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps, SkChunkAlloc* allocator) const { overlaps->fHead = overlaps->fTop = nullptr; SkDEBUGCODE_(overlaps->debugSetGlobalState(fDebugState)); SkCoincidentSpans* outer = fHead; @@ -563,18 +570,21 @@ void SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps, SkChunkAlloc* allo || (outerOpp == innerOpp && SkOpPtT::Overlaps(outer->fOppPtTStart, outer->fOppPtTEnd, inner->fOppPtTStart, inner->fOppPtTEnd, &overlapS, &overlapE))) { - overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp, - overlapS, overlapE, allocator); + if (!overlaps->addOverlap(outerCoin, outerOpp, innerCoin, innerOpp, + overlapS, overlapE, allocator)) { + return false; + } } } outer = outer->fNext; } + return true; } -void SkOpCoincidence::fixAligned() { +bool SkOpCoincidence::fixAligned() { SkCoincidentSpans* coin = fHead; if (!coin) { - return; + return true; } do { if (coin->fCoinPtTStart->deleted()) { @@ -593,6 +603,12 @@ void SkOpCoincidence::fixAligned() { coin = fHead; SkCoincidentSpans** priorPtr = &fHead; do { + if (coin->fCoinPtTStart == coin->fCoinPtTEnd) { + return false; + } + if (coin->fOppPtTStart == coin->fOppPtTEnd) { + return false; + } if (coin->fCoinPtTStart->collapsed(coin->fCoinPtTEnd) || coin->fOppPtTStart->collapsed(coin->fOppPtTEnd)) { *priorPtr = coin->fNext; @@ -600,6 +616,7 @@ void SkOpCoincidence::fixAligned() { } priorPtr = &coin->fNext; } while ((coin = coin->fNext)); + return true; } void SkOpCoincidence::fixUp(SkOpPtT* deleted, SkOpPtT* kept) { diff --git a/src/pathops/SkOpCoincidence.h b/src/pathops/SkOpCoincidence.h index 344866f..1efe6c0 100644 --- a/src/pathops/SkOpCoincidence.h +++ b/src/pathops/SkOpCoincidence.h @@ -84,8 +84,8 @@ public: bool expand(); bool extend(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, SkOpPtT* oppPtTEnd); - void findOverlaps(SkOpCoincidence* , SkChunkAlloc* allocator) const; - void fixAligned(); + bool findOverlaps(SkOpCoincidence* , SkChunkAlloc* allocator) const; + bool fixAligned(); void fixUp(SkOpPtT* deleted, SkOpPtT* kept); bool isEmpty() const { @@ -103,7 +103,7 @@ private: SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd, SkChunkAlloc* ); - void addOverlap(SkOpSegment* seg1, SkOpSegment* seg1o, SkOpSegment* seg2, SkOpSegment* seg2o, + bool addOverlap(SkOpSegment* seg1, SkOpSegment* seg1o, SkOpSegment* seg2, SkOpSegment* seg2o, SkOpPtT* overS, SkOpPtT* overE, SkChunkAlloc* ); bool debugAddIfMissing(const SkCoincidentSpans* outer, const SkOpPtT* over1s, const SkOpPtT* over1e) const; diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp index 340b306..ec8e78d 100644 --- a/src/pathops/SkPathOpsCommon.cpp +++ b/src/pathops/SkPathOpsCommon.cpp @@ -466,7 +466,9 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby"); align(contourList); // give all span members common values DEBUG_COINCIDENCE_HEALTH(contourList, "align"); - coincidence->fixAligned(); // aligning may have marked a coincidence pt-t deleted + if (!coincidence->fixAligned()) { // aligning may have marked a coincidence pt-t deleted + return false; + } DEBUG_COINCIDENCE_HEALTH(contourList, "fixAligned"); #if DEBUG_VALIDATE globalState->setPhase(SkOpGlobalState::kIntersecting); @@ -480,7 +482,9 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby2"); align(contourList); // give all span members common values DEBUG_COINCIDENCE_HEALTH(contourList, "align2"); - coincidence->fixAligned(); // aligning may have marked a coincidence pt-t deleted + if (!coincidence->fixAligned()) { // aligning may have marked a coincidence pt-t deleted + return false; + } DEBUG_COINCIDENCE_HEALTH(contourList, "fixAligned2"); } #if DEBUG_VALIDATE @@ -520,7 +524,9 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->apply"); // For each coincident pair that overlaps another, when the receivers (the 1st of the pair) // are different, construct a new pair to resolve their mutual span - pairs->findOverlaps(&overlaps, allocator); + if (!pairs->findOverlaps(&overlaps, allocator)) { + return false; + } DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->findOverlaps"); } while (!overlaps.isEmpty()); calcAngles(contourList, allocator); diff --git a/src/pathops/SkPathOpsCommon.h b/src/pathops/SkPathOpsCommon.h index 856a984..5b4902f 100644 --- a/src/pathops/SkPathOpsCommon.h +++ b/src/pathops/SkPathOpsCommon.h @@ -25,8 +25,8 @@ SkOpSegment* FindUndone(SkOpContourHead* , SkOpSpanBase** startPtr, 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(bool skipAssert) +bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result + SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)); #if DEBUG_ACTIVE_SPANS void DebugShowActiveSpans(SkOpContourHead* ); diff --git a/src/pathops/SkPathOpsConic.cpp b/src/pathops/SkPathOpsConic.cpp index 86bad26..dd52321 100644 --- a/src/pathops/SkPathOpsConic.cpp +++ b/src/pathops/SkPathOpsConic.cpp @@ -34,7 +34,10 @@ int SkDConic::FindExtrema(const double src[], SkScalar w, double t[1]) { double tValues[2]; int roots = SkDQuad::RootsValidT(coeff[0], coeff[1], coeff[2], tValues); - SkASSERT(0 == roots || 1 == roots); + // In extreme cases, the number of roots returned can be 2. Pathops + // will fail later on, so there's no advantage to plumbing in an error + // return here. + // SkASSERT(0 == roots || 1 == roots); if (1 == roots) { t[0] = tValues[0]; diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp index b71ca9e..2579504 100644 --- a/src/pathops/SkPathOpsOp.cpp +++ b/src/pathops/SkPathOpsOp.cpp @@ -245,8 +245,8 @@ extern void (*gVerboseFinalize)(); #endif -bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result, - bool expectSuccess SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)) { +bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result + SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)) { SkChunkAlloc allocator(4096); // FIXME: add a constant expression here, tune SkOpContour contour; SkOpContourHead* contourList = static_cast(&contour); @@ -413,7 +413,7 @@ static int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBit bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { #if DEBUG_VERIFY - if (!OpDebug(one, two, op, result, true SkDEBUGPARAMS(nullptr))) { + if (!OpDebug(one, two, op, result SkDEBUGPARAMS(nullptr))) { SkDebugf("%s did not expect failure\none: fill=%d\n", __FUNCTION__, one.getFillType()); one.dumpHex(); SkDebugf("two: fill=%d\n", two.getFillType()); @@ -455,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(false) SkDEBUGPARAMS(nullptr)); + return OpDebug(one, two, op, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)); #endif } diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp index 5727660..b71b115 100644 --- a/tests/PathOpsExtendedTest.cpp +++ b/tests/PathOpsExtendedTest.cpp @@ -487,8 +487,8 @@ 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(bool skipAssert) +bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result + SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)); static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, @@ -497,10 +497,12 @@ static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkP showName(a, b, shapeOp); #endif SkPath out; - if (!OpDebug(a, b, shapeOp, &out, expectSuccess SkDEBUGPARAMS(skipAssert) + if (!OpDebug(a, b, shapeOp, &out SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName))) { - SkDebugf("%s did not expect failure\n", __FUNCTION__); - REPORTER_ASSERT(reporter, 0); + if (expectSuccess) { + SkDebugf("%s did not expect failure\n", __FUNCTION__); + REPORTER_ASSERT(reporter, 0); + } return false; } if (!reporter->verbose()) { @@ -556,6 +558,11 @@ bool testPathSkipAssertOp(skiatest::Reporter* reporter, const SkPath& a, const S return innerPathOp(reporter, a, b, shapeOp, testName, true, true); } +bool testPathFailSkipAssertOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, + const SkPathOp shapeOp, const char* testName) { + return innerPathOp(reporter, a, b, shapeOp, testName, false, true); +} + bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const char* testName) { #if DEBUG_SHOW_TEST_NAME diff --git a/tests/PathOpsExtendedTest.h b/tests/PathOpsExtendedTest.h index 0a6f4ab..1fadeb8 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 testPathFailSkipAssertOp(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, diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp index d75c9a6..a73bdcf 100644 --- a/tests/PathOpsOpTest.cpp +++ b/tests/PathOpsOpTest.cpp @@ -5884,7 +5884,70 @@ SkPath path2(path); testPathFailOp(reporter, path1, path2, kUnion_SkPathOp, filename); } +static void fuzz763_9(skiatest::Reporter* reporter, const char* filename) { + SkPath path; + path.setFillType((SkPath::FillType) 1); + + SkPath path1(path); + path.reset(); + path.setFillType((SkPath::FillType) 0); +path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0 +path.conicTo(SkBits2Float(0x2a8c555b), SkBits2Float(0x081f2a21), SkBits2Float(0x7bc00321), SkBits2Float(0xed7a6a4b), SkBits2Float(0x1f212a8c)); // 2.49282e-13f, 4.78968e-34f, 1.99397e+36f, -4.84373e+27f, 3.41283e-20f +path.lineTo(SkBits2Float(0x7bc00321), SkBits2Float(0xed7a6a4b)); // 1.99397e+36f, -4.84373e+27f +path.lineTo(SkBits2Float(0x282a3a21), SkBits2Float(0x3a21df28)); // 9.4495e-15f, 0.000617492f +path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0 +path.close(); +path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0 +path.quadTo(SkBits2Float(0x8a284f9a), SkBits2Float(0x3ac23ab3), SkBits2Float(0x1d2a2928), SkBits2Float(0x63962be6)); // -8.10388e-33f, 0.00148185f, 2.25206e-21f, 5.54035e+21f +path.moveTo(SkBits2Float(0x29272a81), SkBits2Float(0x2ab03a55)); // 3.71183e-14f, 3.13044e-13f +path.quadTo(SkBits2Float(0x2720213b), SkBits2Float(0x3a214729), SkBits2Float(0xdf28282a), SkBits2Float(0x8a2f2121)); // 2.22225e-15f, 0.000615227f, -1.2117e+19f, -8.43217e-33f +path.quadTo(SkBits2Float(0x373b3a27), SkBits2Float(0x201fc4c1), SkBits2Float(0x27576c2a), SkBits2Float(0x5921c25d)); // 1.11596e-05f, 1.35329e-19f, 2.98959e-15f, 2.8457e+15f +path.quadTo(SkBits2Float(0x2720213b), SkBits2Float(0x3a214729), SkBits2Float(0xdf28282a), SkBits2Float(0x3a8a3a21)); // 2.22225e-15f, 0.000615227f, -1.2117e+19f, 0.00105459f +path.cubicTo(SkBits2Float(0x373b3ac5), SkBits2Float(0x201fc422), SkBits2Float(0x523a702a), SkBits2Float(0x27576c51), SkBits2Float(0x5921c25d), SkBits2Float(0x51523a70)); // 1.11598e-05f, 1.35327e-19f, 2.00186e+11f, 2.9896e-15f, 2.8457e+15f, 5.64327e+10f +path.quadTo(SkBits2Float(0xd912102a), SkBits2Float(0x284f9a28), SkBits2Float(0xb38a1f30), SkBits2Float(0x3a3ac23a)); // -2.56957e+15f, 1.15242e-14f, -6.4318e-08f, 0.000712428f +path.lineTo(SkBits2Float(0xc809272a), SkBits2Float(0x29b02829)); // -140445, 7.82294e-14f + + SkPath path2(path); + testPathFailOp(reporter, path1, path2, (SkPathOp) 1, filename); +} + + +static void fuzz763_4(skiatest::Reporter* reporter, const char* filename) { + SkPath path; + path.setFillType((SkPath::FillType) 1); + + SkPath path1(path); + path.reset(); + path.setFillType((SkPath::FillType) 0); +path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0 +path.lineTo(SkBits2Float(0x555b3a2d), SkBits2Float(0x2a212a8c)); // 1.50652e+13f, 1.43144e-13f +path.conicTo(SkBits2Float(0xc0032108), SkBits2Float(0x7a6a4b7b), SkBits2Float(0x212a8ced), SkBits2Float(0x0321081f), SkBits2Float(0x6a3a7bc0)); // -2.04889f, 3.04132e+35f, 5.77848e-19f, 4.7323e-37f, 5.63611e+25f +path.conicTo(SkBits2Float(0x3a2147ed), SkBits2Float(0xdf28282a), SkBits2Float(0x3a8a3a21), SkBits2Float(0x8a284f9a), SkBits2Float(0x3ac2b33a)); // 0.000615238f, -1.2117e+19f, 0.00105459f, -8.10388e-33f, 0.00148544f +path.cubicTo(SkBits2Float(0x1d2a2928), SkBits2Float(0x63962be6), SkBits2Float(0x295b2d2a), SkBits2Float(0x68295b2d), SkBits2Float(0x2d296855), SkBits2Float(0x2a8c275b)); // 2.25206e-21f, 5.54035e+21f, 4.86669e-14f, 3.19905e+24f, 9.6297e-12f, 2.48963e-13f +path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0 +path.close(); +path.moveTo(SkBits2Float(0x55685b1f), SkBits2Float(0x5b2d2968)); // 1.59674e+13f, 4.87407e+16f +path.lineTo(SkBits2Float(0x2a212a8c), SkBits2Float(0x2a21081f)); // 1.43144e-13f, 1.43025e-13f +path.conicTo(SkBits2Float(0xde6a4b7b), SkBits2Float(0x2a8ced7a), SkBits2Float(0x21081f21), SkBits2Float(0x3a7bc003), SkBits2Float(0x47ed7a6a)); // -4.22068e+18f, 2.50338e-13f, 4.61198e-19f, 0.00096035f, 121589 +path.lineTo(SkBits2Float(0x55685b1f), SkBits2Float(0x5b2d2968)); // 1.59674e+13f, 4.87407e+16f +path.close(); +path.moveTo(SkBits2Float(0x55685b1f), SkBits2Float(0x5b2d2968)); // 1.59674e+13f, 4.87407e+16f +path.quadTo(SkBits2Float(0xdf28282a), SkBits2Float(0x3a8a3a21), SkBits2Float(0x8a284f9a), SkBits2Float(0x3ac23ab3)); // -1.2117e+19f, 0.00105459f, -8.10388e-33f, 0.00148185f +path.lineTo(SkBits2Float(0x2928088c), SkBits2Float(0x2be61d2a)); // 3.73109e-14f, 1.63506e-12f +path.conicTo(SkBits2Float(0x2a812a63), SkBits2Float(0x2d292a27), SkBits2Float(0x5568295b), SkBits2Float(0x5b2d2968), SkBits2Float(0x552d6829)); // 2.29444e-13f, 9.6159e-12f, 1.5954e+13f, 4.87407e+16f, 1.19164e+13f +path.conicTo(SkBits2Float(0x395b2d5b), SkBits2Float(0x68552768), SkBits2Float(0x555b2df0), SkBits2Float(0x1f722a8c), SkBits2Float(0x082a212a)); // 0.000209024f, 4.02636e+24f, 1.50619e+13f, 5.12807e-20f, 5.11965e-34f +path.lineTo(SkBits2Float(0x55685b1f), SkBits2Float(0x5b2d2968)); // 1.59674e+13f, 4.87407e+16f +path.close(); +path.moveTo(SkBits2Float(0x212a8c55), SkBits2Float(0x21081f2a)); // 5.7784e-19f, 4.61198e-19f +path.conicTo(SkBits2Float(0x6a4b7bc0), SkBits2Float(0x2147ed7a), SkBits2Float(0x28282a3a), SkBits2Float(0x21df212a), SkBits2Float(0x033a8a3a)); // 6.14991e+25f, 6.77381e-19f, 9.33503e-15f, 1.51198e-18f, 5.48192e-37f + + SkPath path2(path); + testPathFailSkipAssertOp(reporter, path1, path2, (SkPathOp) 1, filename); +} + static struct TestDesc failTests[] = { + TEST(fuzz763_4), + TEST(fuzz763_9), TEST(fuzz1450_1), TEST(fuzz1450_0), TEST(bug597926_0), -- 2.7.4