aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2016-06-08 04:28:19 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-06-08 04:28:19 -0700
commitdae6b97705fde08958b1a36fa6ce685d28fc692c (patch)
tree39b7c096c331a0a29a43ddc7455705f821f5f640
parent2af4599b5c514933bf997d4837ddaaf24fc61cd7 (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.cpp2
-rw-r--r--src/pathops/SkDConicLineIntersection.cpp11
-rw-r--r--src/pathops/SkIntersections.h8
-rw-r--r--src/pathops/SkOpBuilder.cpp19
-rwxr-xr-xsrc/pathops/SkOpCoincidence.cpp3
-rw-r--r--src/pathops/SkPathOpsCommon.cpp3
-rw-r--r--src/pathops/SkPathOpsCommon.h5
-rw-r--r--src/pathops/SkPathOpsOp.cpp7
-rw-r--r--src/pathops/SkPathOpsSimplify.cpp3
-rw-r--r--src/pathops/SkPathOpsTightBounds.cpp3
-rw-r--r--src/pathops/SkPathOpsTypes.cpp4
-rw-r--r--src/pathops/SkPathOpsTypes.h3
-rwxr-xr-xtests/PathOpsAngleIdeas.cpp2
-rw-r--r--tests/PathOpsAngleTest.cpp4
-rw-r--r--tests/PathOpsBuilderTest.cpp22
-rw-r--r--tests/PathOpsExtendedTest.cpp19
-rw-r--r--tests/PathOpsExtendedTest.h2
-rw-r--r--tests/PathOpsOpTest.cpp50
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),