aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2016-07-21 05:48:43 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-07-21 05:48:44 -0700
commit1597628fa38d24f23ad505bfb40e70e7c8617457 (patch)
tree1404694d03aa87c0d78d73701b710f4ab880f4bc
parentec336deffbf5945f2249f822b1ccc4628a9906a4 (diff)
fix fuzzer bug
Fix another fuzzer bug. Some PathOps asserts only make sense if the incoming data is well-behaved. Well-behaved tests set debugging state to trigger these additional asserts. Formalize this by creating macros similar to SkASSERT that check to see if the assert should be skipped. TBR=reed@google.com BUG=629962 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2169863002 Review-Url: https://codereview.chromium.org/2169863002
-rw-r--r--src/pathops/SkDConicLineIntersection.cpp6
-rwxr-xr-xsrc/pathops/SkOpCoincidence.cpp19
-rw-r--r--src/pathops/SkOpCoincidence.h2
-rw-r--r--src/pathops/SkOpSegment.cpp2
-rw-r--r--src/pathops/SkOpSegment.h2
-rwxr-xr-xsrc/pathops/SkOpSpan.cpp2
-rw-r--r--src/pathops/SkPathOpsTypes.h4
-rw-r--r--tests/PathOpsOpTest.cpp56
8 files changed, 80 insertions, 13 deletions
diff --git a/src/pathops/SkDConicLineIntersection.cpp b/src/pathops/SkDConicLineIntersection.cpp
index 620e99c8ae..a70307a53e 100644
--- a/src/pathops/SkDConicLineIntersection.cpp
+++ b/src/pathops/SkDConicLineIntersection.cpp
@@ -80,7 +80,7 @@ public:
double conicT = roots[index];
SkDPoint pt = fConic.ptAtT(conicT);
SkDEBUGCODE_(double conicVals[] = { fConic[0].fY, fConic[1].fY, fConic[2].fY });
- SkASSERT(close_to(pt.fY, axisIntercept, conicVals));
+ SkOPOBJASSERT(fIntersections, close_to(pt.fY, axisIntercept, conicVals));
double lineT = (pt.fX - left) / (right - left);
if (this->pinTs(&conicT, &lineT, &pt, kPointInitialized)
&& this->uniqueAnswer(conicT, pt)) {
@@ -158,9 +158,7 @@ public:
double conicT = roots[index];
SkDPoint pt = fConic.ptAtT(conicT);
SkDEBUGCODE_(double conicVals[] = { fConic[0].fX, fConic[1].fX, fConic[2].fX });
- SkASSERT((fIntersections->debugGlobalState() &&
- fIntersections->debugGlobalState()->debugSkipAssert()) ||
- close_to(pt.fX, axisIntercept, conicVals));
+ SkOPOBJASSERT(fIntersections, 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 af330dfe1e..d750ce78b9 100755
--- a/src/pathops/SkOpCoincidence.cpp
+++ b/src/pathops/SkOpCoincidence.cpp
@@ -268,7 +268,7 @@ void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* o
}
// description below
-void SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
+bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan) {
const SkOpPtT* testPtT = testSpan->ptT();
const SkOpPtT* stopPtT = testPtT;
const SkOpSegment* baseSeg = base->segment();
@@ -324,9 +324,12 @@ void SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase*
SkTSwap(coinTs, coinTe);
SkTSwap(oppTs, oppTe);
}
- (void) this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe);
+ if (!this->addOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe)) {
+ return false;
+ }
}
}
+ return true;
}
// description below
@@ -337,10 +340,14 @@ bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
return false;
}
if (!prev->isCanceled()) {
- this->addEndMovedSpans(base, base->prev());
+ if (!this->addEndMovedSpans(base, base->prev())) {
+ return false;
+ }
}
if (!base->isCanceled()) {
- this->addEndMovedSpans(base, base->next());
+ if (!this->addEndMovedSpans(base, base->next())) {
+ return false;
+ }
}
return true;
}
@@ -631,7 +638,9 @@ bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
if (overlap && cs && ce && overlap->contains(cs, ce)) {
return false;
}
- SkASSERT(cs != ce || !cs);
+ if (cs == ce && cs) {
+ return false;
+ }
const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
if (overlap && os && oe && overlap->contains(os, oe)) {
diff --git a/src/pathops/SkOpCoincidence.h b/src/pathops/SkOpCoincidence.h
index c64d148c24..22a96c18f0 100644
--- a/src/pathops/SkOpCoincidence.h
+++ b/src/pathops/SkOpCoincidence.h
@@ -230,7 +230,7 @@ private:
const_cast<SkOpPtT*>(oppPtTStart), const_cast<SkOpPtT*>(oppPtTEnd));
}
- void addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan);
+ bool addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan);
bool addEndMovedSpans(const SkOpPtT* ptT);
bool addIfMissing(const SkCoincidentSpans* outer, SkOpPtT* over1s, SkOpPtT* over1e);
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index e4e00bbfab..3fc21f4490 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -541,7 +541,7 @@ void SkOpSegment::release(const SkOpSpan* span) {
--fDoneCount;
}
--fCount;
- SkASSERT(this->globalState()->debugSkipAssert() || fCount >= fDoneCount);
+ SkOPASSERT(fCount >= fDoneCount);
}
double SkOpSegment::distSq(double t, const SkOpAngle* oppAngle) const {
diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h
index 55e67a5d80..7cf4b269f0 100644
--- a/src/pathops/SkOpSegment.h
+++ b/src/pathops/SkOpSegment.h
@@ -186,7 +186,7 @@ public:
double distSq(double t, const SkOpAngle* opp) const;
bool done() const {
- SkASSERT(this->globalState()->debugSkipAssert() || fDoneCount <= fCount);
+ SkOPASSERT(fDoneCount <= fCount);
return fDoneCount == fCount;
}
diff --git a/src/pathops/SkOpSpan.cpp b/src/pathops/SkOpSpan.cpp
index 1cdfe91a24..8937bdd5bb 100755
--- a/src/pathops/SkOpSpan.cpp
+++ b/src/pathops/SkOpSpan.cpp
@@ -173,7 +173,7 @@ SkOpSegment* SkOpPtT::segment() {
void SkOpPtT::setDeleted() {
SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this);
- SkASSERT(this->globalState()->debugSkipAssert() || !fDeleted);
+ SkOPASSERT(!fDeleted);
fDeleted = true;
}
diff --git a/src/pathops/SkPathOpsTypes.h b/src/pathops/SkPathOpsTypes.h
index ad2ad463e6..ad9c931795 100644
--- a/src/pathops/SkPathOpsTypes.h
+++ b/src/pathops/SkPathOpsTypes.h
@@ -183,6 +183,10 @@ private:
#endif
};
+#define SkOPASSERT(cond) SkASSERT(this->globalState()->debugSkipAssert() || cond)
+#define SkOPOBJASSERT(obj, cond) SkASSERT((obj->debugGlobalState() && \
+ obj->debugGlobalState()->debugSkipAssert()) || cond)
+
// Use Almost Equal when comparing coordinates. Use epsilon to compare T values.
bool AlmostEqualUlps(float a, float b);
inline bool AlmostEqualUlps(double a, double b) {
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 0f3c50e493..2cc9f28baf 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -5347,6 +5347,7 @@ static void cubics_d3(skiatest::Reporter* reporter, const char* filename) {
pathB.cubicTo(2, 4, 4, 3, 6, 0);
pathB.close();
// DEBUG_UNDER_DEVELOPMENT cubics_d3 disable expectation check for now
+ // fails because segment 3 is marked as unorderable ?
testPathOpCheck(reporter, path, pathB, kDifference_SkPathOp, filename, !FLAGS_runFail);
}
@@ -6445,7 +6446,62 @@ path.lineTo(SkBits2Float(0x63962be6), SkBits2Float(0x272a812a)); // 5.54035e+21
testPathOpFail(reporter, path1, path2, (SkPathOp) 0, filename);
}
+static void fuzz763_7(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.setFillType((SkPath::FillType) 0);
+
+ SkPath path1(path);
+ path.reset();
+ path.setFillType((SkPath::FillType) 0);
+path.moveTo(SkBits2Float(0x68556829), SkBits2Float(0x555b2d29)); // 4.03114e+24f, 1.50617e+13f
+path.moveTo(SkBits2Float(0x0f2a312a), SkBits2Float(0xc0032108)); // 8.39112e-30f, -2.04889f
+path.cubicTo(SkBits2Float(0x68392d55), SkBits2Float(0xf05b684b), SkBits2Float(0x8c55272d), SkBits2Float(0x212a1f2a), SkBits2Float(0x0321082a), SkBits2Float(0x6a4b7bc0)); // 3.4979e+24f, -2.71613e+29f, -1.64207e-31f, 5.76395e-19f, 4.7323e-37f, 6.14991e+25f
+path.conicTo(SkBits2Float(0x212a8ced), SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0), SkBits2Float(0x2829ed84), SkBits2Float(0x2d555b2d)); // 5.77848e-19f, 4.7323e-37f, 6.14991e+25f, 9.43289e-15f, 1.21279e-11f
+path.moveTo(SkBits2Float(0x68345b2d), SkBits2Float(0xf0682955)); // 3.40683e+24f, -2.87402e+29f
+path.conicTo(SkBits2Float(0x212a1f5b), SkBits2Float(0xef2a8c55), SkBits2Float(0x295b2d2a), SkBits2Float(0x08685568), SkBits2Float(0x7bc00321)); // 5.76397e-19f, -5.27821e+28f, 4.86669e-14f, 6.99154e-34f, 1.99397e+36f
+path.lineTo(SkBits2Float(0x68345b2d), SkBits2Float(0xf0682955)); // 3.40683e+24f, -2.87402e+29f
+path.close();
+path.moveTo(SkBits2Float(0x68345b2d), SkBits2Float(0xf0682955)); // 3.40683e+24f, -2.87402e+29f
+path.lineTo(SkBits2Float(0x5b2c6829), SkBits2Float(0x212a8c55)); // 4.85282e+16f, 5.7784e-19f
+path.moveTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.lineTo(SkBits2Float(0x3a8a3adf), SkBits2Float(0x8a281a4f)); // 0.00105461f, -8.09385e-33f
+path.quadTo(SkBits2Float(0x1d2a2928), SkBits2Float(0x43962be6), SkBits2Float(0x272a812a), SkBits2Float(0x3a2a5529)); // 2.25206e-21f, 300.343f, 2.36623e-15f, 0.000649768f
+path.lineTo(SkBits2Float(0x213b1e2a), SkBits2Float(0x27292720)); // 6.3398e-19f, 2.34747e-15f
+path.conicTo(SkBits2Float(0xba1f203a), SkBits2Float(0xc422c538), SkBits2Float(0x215d5927), SkBits2Float(0x70ec2ac2), SkBits2Float(0x2a51523a)); // -0.000607017f, -651.082f, 7.49957e-19f, 5.84721e+29f, 1.85915e-13f
+path.quadTo(SkBits2Float(0x633ad912), SkBits2Float(0x29c80927), SkBits2Float(0x272927b0), SkBits2Float(0x683a5b2d)); // 3.44674e+21f, 8.88337e-14f, 2.3475e-15f, 3.52017e+24f
+path.lineTo(SkBits2Float(0x295b2d68), SkBits2Float(0x29685568)); // 4.86672e-14f, 5.15884e-14f
+path.conicTo(SkBits2Float(0xaa8c555b), SkBits2Float(0x081f2a21), SkBits2Float(0x5b2d0321), SkBits2Float(0x68556829), SkBits2Float(0x2a552d29)); // -2.49282e-13f, 4.78968e-34f, 4.86986e+16f, 4.03114e+24f, 1.89339e-13f
+path.cubicTo(SkBits2Float(0x21295b2d), SkBits2Float(0x2a688c5b), SkBits2Float(0x68295b2d), SkBits2Float(0x2d296855), SkBits2Float(0x8c08555b), SkBits2Float(0x2a2a29ca)); // 5.73801e-19f, 2.06544e-13f, 3.19905e+24f, 9.6297e-12f, -1.05027e-31f, 1.51135e-13f
+path.quadTo(SkBits2Float(0x68295b21), SkBits2Float(0x2d296855), SkBits2Float(0x2a8c555b), SkBits2Float(0x081f2a21)); // 3.19904e+24f, 9.6297e-12f, 2.49282e-13f, 4.78968e-34f
+path.lineTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.close();
+path.moveTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.conicTo(SkBits2Float(0x6a4b7bc0), SkBits2Float(0x5b2d6829), SkBits2Float(0x212a8c55), SkBits2Float(0xed7aba1f), SkBits2Float(0x2a212a8c)); // 6.14991e+25f, 4.88097e+16f, 5.7784e-19f, -4.84977e+27f, 1.43144e-13f
+path.moveTo(SkBits2Float(0x2d212d08), SkBits2Float(0x5568295b)); // 9.16179e-12f, 1.5954e+13f
+path.moveTo(SkBits2Float(0x5529685b), SkBits2Float(0x11295b68)); // 1.16416e+13f, 1.33599e-28f
+path.conicTo(SkBits2Float(0x5b782968), SkBits2Float(0x3a292d55), SkBits2Float(0x2a8c555b), SkBits2Float(0x68295a2d), SkBits2Float(0x2d296855)); // 6.98513e+16f, 0.000645359f, 2.49282e-13f, 3.19897e+24f, 9.6297e-12f
+path.moveTo(SkBits2Float(0x555b8c55), SkBits2Float(0x21682929)); // 1.50872e+13f, 7.86591e-19f
+path.moveTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.conicTo(SkBits2Float(0xac2d8ced), SkBits2Float(0x5b682968), SkBits2Float(0x5b292d55), SkBits2Float(0x212a8c55), SkBits2Float(0x081f282a)); // -2.4663e-12f, 6.53477e+16f, 4.76191e+16f, 5.7784e-19f, 4.78945e-34f
+path.lineTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.close();
+path.moveTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.conicTo(SkBits2Float(0x6a4b7bc0), SkBits2Float(0x2a8ced7a), SkBits2Float(0x03081f21), SkBits2Float(0x6a3a7bc0), SkBits2Float(0x2147ed7a)); // 6.14991e+25f, 2.50338e-13f, 4.00025e-37f, 5.63611e+25f, 6.77381e-19f
+path.lineTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.close();
+path.moveTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.quadTo(SkBits2Float(0x2d28282a), SkBits2Float(0x5568295b), SkBits2Float(0x3a21df68), SkBits2Float(0x4f9a3a8a)); // 9.55861e-12f, 1.5954e+13f, 0.000617495f, 5.17506e+09f
+path.lineTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.close();
+path.moveTo(SkBits2Float(0x0321081f), SkBits2Float(0x6a4b7bc0)); // 4.7323e-37f, 6.14991e+25f
+path.cubicTo(SkBits2Float(0x5568c23a), SkBits2Float(0x5b2d2968), SkBits2Float(0x212a8c55), SkBits2Float(0x21081f2a), SkBits2Float(0x3a7bc003), SkBits2Float(0x294b2827)); // 1.59951e+13f, 4.87407e+16f, 5.7784e-19f, 4.61198e-19f, 0.00096035f, 4.51099e-14f
+
+ SkPath path2(path);
+ testPathOpFail(reporter, path1, path2, (SkPathOp) 0, filename);
+}
+
static struct TestDesc failTests[] = {
+ TEST(fuzz763_7),
TEST(fuzz763_6),
TEST(fuzz763_2c),
TEST(fuzz763_2b),