fix pathops timeouts

R=kjlubick@google.com

Bug: skia:8475
Change-Id: I88a440d55872e8f655236b86e30a95bff1fef695
Reviewed-on: https://skia-review.googlesource.com/c/163128
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Cary Clark <caryclark@skia.org>
diff --git a/src/pathops/SkOpCoincidence.cpp b/src/pathops/SkOpCoincidence.cpp
index f0857c7..176d355 100644
--- a/src/pathops/SkOpCoincidence.cpp
+++ b/src/pathops/SkOpCoincidence.cpp
@@ -813,7 +813,15 @@
         SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
         SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
         SkCoincidentSpans* inner = outer;
+#ifdef IS_FUZZING_WITH_LIBFUZZER
+        int safetyNet = 1000;
+#endif
         while ((inner = inner->next())) {
+#ifdef IS_FUZZING_WITH_LIBFUZZER
+            if (!--safetyNet) {
+                return false;
+            }
+#endif
             this->debugValidate();
             double overS, overE;
             const SkOpPtT* ics = inner->coinPtTStart();
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index e35f6d0..89a39b4 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -921,7 +921,11 @@
     bool success = markWinding(spanStart, winding, oppWinding);
     SkOpSpanBase* last = nullptr;
     SkOpSegment* other = this;
+    int safetyNet = 100000;
     while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
+        if (!--safetyNet) {
+            return false;
+        }
         if (spanStart->windSum() != SK_MinS32) {
             if (this->operand() == other->operand()) {
                 if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
diff --git a/src/pathops/SkOpSpan.cpp b/src/pathops/SkOpSpan.cpp
index cb2e7fb..9fa05f1 100644
--- a/src/pathops/SkOpSpan.cpp
+++ b/src/pathops/SkOpSpan.cpp
@@ -166,7 +166,11 @@
     double min = walk->fT;
     double max = min;
     const SkOpSegment* segment = this->segment();
+    int safetyNet = 100000;
     while ((walk = walk->next()) != start) {
+        if (!--safetyNet) {
+            return Collapsed::kError;
+        }
         if (walk == startNext) {
             return Collapsed::kError;
         }
diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h
index 57f158e..6825daa 100644
--- a/src/pathops/SkPathOpsDebug.h
+++ b/src/pathops/SkPathOpsDebug.h
@@ -31,6 +31,9 @@
 struct SkDCubic;
 class SkTSect;
 
+// define this when running fuzz
+// #define IS_FUZZING_WITH_LIBFUZZER
+
 // dummy classes to fool msvs Visual Studio 2018 Immediate Window
 #define DummyClasses(a, b) \
 class SkDebugTCoincident##a##b; \
diff --git a/src/pathops/SkPathOpsTSect.cpp b/src/pathops/SkPathOpsTSect.cpp
index 6149bc5..9560f69 100644
--- a/src/pathops/SkPathOpsTSect.cpp
+++ b/src/pathops/SkPathOpsTSect.cpp
@@ -725,6 +725,9 @@
 
 void SkTSect::computePerpendiculars(SkTSect* sect2,
         SkTSpan* first, SkTSpan* last) {
+    if (!last) {
+        return;
+    }
     const SkTCurve& opp = sect2->fCurve;
     SkTSpan* work = first;
     SkTSpan* prior = nullptr;
@@ -1461,7 +1464,11 @@
 SkTSpan* SkTSect::tail() {
     SkTSpan* result = fHead;
     SkTSpan* next = fHead;
+    int safetyNet = 100000;
     while ((next = next->fNext)) {
+        if (!--safetyNet) {
+            return nullptr;
+        }
         if (next->fEndT > result->fEndT) {
             result = next;
         }