diff options
author | Cary Clark <caryclark@skia.org> | 2018-03-14 15:55:02 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-15 17:07:16 +0000 |
commit | b8421edb47e9b3831df64d03a00f15509c2bebaa (patch) | |
tree | c06608d81848316c8a8c1a57938a72911d99ac00 /src/pathops | |
parent | c2ec4e8d83e42d7059528e3ccc7c3ab584ed1f31 (diff) |
fix pathops fuzzers and debugging
En route to fixing fuzzer bugs, I discovered that most
debugging in pathops was broken. Pathops has extensive
runtime functions that trace links and connections between
data structures that are invaluable to debugging. The
only practical way to use these functions is to call them
from the debugger in immediate mode.
Some time, some where, the MSVS Immediate Window ceased
to be able to call functions that are members of structs
or classes, and functions that take templated parameters.
I can find no mention of this on the web, so I assume
that something about our setup is triggering this, but
I've had no luck finding the culprit.
In the meantime, I've added global functions wrapped in
a namespace to sneak calls to these functions without
MSVS being any the wiser. While this works, it is likely
to bitrot by tomorrow or next Tuesday so I will continue
to try to find and fix the root cause.
This also fixes the fuzzer bugs; generally one-line edits
that change asserts to fails. All pathops tests succeed
with this. To run all tests, do:
./out/debug/pathops_unittest -V -x
./out/release/pathops_unittest -V -x
TBR=caryclark@google.com
Bug: skia:
Change-Id: I956ae3d8df6d25e155e62bd6dede64519c7fbdb1
Reviewed-on: https://skia-review.googlesource.com/114321
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Reviewed-by: Cary Clark <caryclark@skia.org>
Commit-Queue: Cary Clark <caryclark@skia.org>
Diffstat (limited to 'src/pathops')
-rw-r--r-- | src/pathops/SkOpCoincidence.cpp | 4 | ||||
-rw-r--r-- | src/pathops/SkPathOpsDebug.cpp | 11 | ||||
-rw-r--r-- | src/pathops/SkPathOpsDebug.h | 235 | ||||
-rw-r--r-- | src/pathops/SkPathOpsTSect.h | 3 |
4 files changed, 186 insertions, 67 deletions
diff --git a/src/pathops/SkOpCoincidence.cpp b/src/pathops/SkOpCoincidence.cpp index 8fa42a5c4e..3251ec4371 100644 --- a/src/pathops/SkOpCoincidence.cpp +++ b/src/pathops/SkOpCoincidence.cpp @@ -691,7 +691,7 @@ bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg, if (overlap && os && oe && overlap->contains(os, oe)) { return true; } - SkASSERT(!cs || !cs->deleted()); + FAIL_IF(cs && cs->deleted()); FAIL_IF(os && os->deleted()); SkASSERT(!ce || !ce->deleted()); FAIL_IF(oe && oe->deleted()); @@ -1098,7 +1098,7 @@ bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { FAIL_IF(windValue == -1); start->setWindValue(windValue); start->setOppValue(oppValue); - FAIL_IF(oWindValue == -1); + FAIL_IF(oWindValue <= -1); oStart->setWindValue(oWindValue); oStart->setOppValue(oOppValue); if (!windValue && !oppValue) { diff --git a/src/pathops/SkPathOpsDebug.cpp b/src/pathops/SkPathOpsDebug.cpp index f13b958a84..346db4b340 100644 --- a/src/pathops/SkPathOpsDebug.cpp +++ b/src/pathops/SkPathOpsDebug.cpp @@ -47,8 +47,6 @@ const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor", "rdi #if defined SK_DEBUG || !FORCE_RELEASE -const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"}; - int SkPathOpsDebug::gContourID = 0; int SkPathOpsDebug::gSegmentID = 0; @@ -3124,3 +3122,12 @@ void SkPathOpsDebug::VerifySimplify(const SkPath& path, const SkPath& result) { } #endif + +// global path dumps for msvs Visual Studio 17 to use from Immediate Window +void Dump(const SkPath& path) { + path.dump(); +} + +void DumpHex(const SkPath& path) { + path.dumpHex(); +} diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h index afdfb32be1..9aec715de1 100644 --- a/src/pathops/SkPathOpsDebug.h +++ b/src/pathops/SkPathOpsDebug.h @@ -14,7 +14,36 @@ #include <stdio.h> enum class SkOpPhase : char; +struct SkDQuad; +class SkOpAngle; +class SkOpCoincidence; +class SkOpContour; class SkOpContourHead; +class SkOpPtT; +class SkOpSegment; +class SkOpSpan; +class SkOpSpanBase; +struct SkDPoint; +struct SkDLine; +struct SkDQuad; +struct SkDConic; +struct SkDCubic; +template<typename TCurve, typename OppCurve> class SkTSect; + +// dummy classes to fool msvs Visual Studio 2018 Immediate Window +#define DummyClasses(a, b) \ +class SkDebugTCoincident##a##b; \ +class SkDebugTSect##a##b; \ +class SkDebugTSpan##a##b + +DummyClasses(Quad, Quad); +DummyClasses(Conic, Quad); +DummyClasses(Conic, Conic); +DummyClasses(Cubic, Quad); +DummyClasses(Cubic, Conic); +DummyClasses(Cubic, Cubic); + +#undef DummyClasses #ifdef SK_RELEASE #define FORCE_RELEASE 1 @@ -97,7 +126,7 @@ class SkOpContourHead; #define DEBUG_PERP 1 #define DEBUG_SHOW_TEST_NAME 1 #define DEBUG_SORT 1 -#define DEBUG_T_SECT 0 +#define DEBUG_T_SECT 0 // enabling may trigger validate asserts even though op does not fail #define DEBUG_T_SECT_DUMP 0 // Use 1 normally. Use 2 to number segments, 3 for script output #define DEBUG_T_SECT_LOOP_COUNT 0 #define DEBUG_VALIDATE 1 @@ -233,8 +262,6 @@ class SkOpContourHead; class SkPathOpsDebug { public: - static const char* kLVerbStr[]; - #if DEBUG_COIN struct GlitchLog; @@ -311,7 +338,18 @@ public: #if DEBUG_ACTIVE_OP static const char* kPathOpStr[]; #endif + static bool gRunFail; + static bool gVeryVerbose; + +#if DEBUG_ACTIVE_SPANS + static SkString gActiveSpans; +#endif +#if DEBUG_DUMP_VERIFY + static bool gDumpOp; + static bool gVerifyOp; +#endif + static const char* OpStr(SkPathOp ); static void MathematicaIze(char* str, size_t bufferSize); static bool ValidWind(int winding); static void WindingPrintf(int winding); @@ -324,86 +362,157 @@ public: SkPathOpsDebug::DeleteNameStr))) static void BumpTestName(char* ); #endif - static const char* OpStr(SkPathOp ); static void ShowActiveSpans(SkOpContourHead* contourList); static void ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration); static void ShowPath(const SkPath& one, const SkPath& two, SkPathOp op, const char* name); - static bool ChaseContains(const SkTDArray<class SkOpSpanBase*>& , const class SkOpSpanBase* ); + static bool ChaseContains(const SkTDArray<SkOpSpanBase*>& , const SkOpSpanBase* ); static void CheckHealth(class SkOpContourHead* contourList); - static const class SkOpAngle* DebugAngleAngle(const class SkOpAngle*, int id); - static class SkOpContour* DebugAngleContour(class SkOpAngle*, int id); - static const class SkOpPtT* DebugAnglePtT(const class SkOpAngle*, int id); - static const class SkOpSegment* DebugAngleSegment(const class SkOpAngle*, int id); - static const class SkOpSpanBase* DebugAngleSpan(const class SkOpAngle*, int id); - - static const class SkOpAngle* DebugContourAngle(class SkOpContour*, int id); - static class SkOpContour* DebugContourContour(class SkOpContour*, int id); - static const class SkOpPtT* DebugContourPtT(class SkOpContour*, int id); - static const class SkOpSegment* DebugContourSegment(class SkOpContour*, int id); - static const class SkOpSpanBase* DebugContourSpan(class SkOpContour*, int id); - - static const class SkOpAngle* DebugCoincidenceAngle(class SkOpCoincidence*, int id); - static class SkOpContour* DebugCoincidenceContour(class SkOpCoincidence*, int id); - static const class SkOpPtT* DebugCoincidencePtT(class SkOpCoincidence*, int id); - static const class SkOpSegment* DebugCoincidenceSegment(class SkOpCoincidence*, int id); - static const class SkOpSpanBase* DebugCoincidenceSpan(class SkOpCoincidence*, int id); - - static const class SkOpAngle* DebugPtTAngle(const class SkOpPtT*, int id); - static class SkOpContour* DebugPtTContour(class SkOpPtT*, int id); - static const class SkOpPtT* DebugPtTPtT(const class SkOpPtT*, int id); - static const class SkOpSegment* DebugPtTSegment(const class SkOpPtT*, int id); - static const class SkOpSpanBase* DebugPtTSpan(const class SkOpPtT*, int id); - - static const class SkOpAngle* DebugSegmentAngle(const class SkOpSegment*, int id); - static class SkOpContour* DebugSegmentContour(class SkOpSegment*, int id); - static const class SkOpPtT* DebugSegmentPtT(const class SkOpSegment*, int id); - static const class SkOpSegment* DebugSegmentSegment(const class SkOpSegment*, int id); - static const class SkOpSpanBase* DebugSegmentSpan(const class SkOpSegment*, int id); - - static const class SkOpAngle* DebugSpanAngle(const class SkOpSpanBase*, int id); - static class SkOpContour* DebugSpanContour(class SkOpSpanBase*, int id); - static const class SkOpPtT* DebugSpanPtT(const class SkOpSpanBase*, int id); - static const class SkOpSegment* DebugSpanSegment(const class SkOpSpanBase*, int id); - static const class SkOpSpanBase* DebugSpanSpan(const class SkOpSpanBase*, int id); - #if DEBUG_COIN - static void DumpCoinDict(); - static void DumpGlitchType(GlitchType ); + static void DumpCoinDict(); + static void DumpGlitchType(GlitchType ); #endif - static bool gRunFail; - static bool gVeryVerbose; +}; -#if DEBUG_DUMP_VERIFY - static bool gDumpOp; - static bool gVerifyOp; +// Visual Studio 2017 does not permit calling member functions from the Immediate Window. +// Global functions work fine, however. Use globals within a namespace rather than +// static members inside a class. +namespace SkOpDebug { + const SkOpAngle* AngleAngle(const SkOpAngle*, int id); + SkOpContour* AngleContour(SkOpAngle*, int id); + const SkOpPtT* AnglePtT(const SkOpAngle*, int id); + const SkOpSegment* AngleSegment(const SkOpAngle*, int id); + const SkOpSpanBase* AngleSpan(const SkOpAngle*, int id); + + const SkOpAngle* ContourAngle(SkOpContour*, int id); + SkOpContour* ContourContour(SkOpContour*, int id); + const SkOpPtT* ContourPtT(SkOpContour*, int id); + const SkOpSegment* ContourSegment(SkOpContour*, int id); + const SkOpSpanBase* ContourSpan(SkOpContour*, int id); + + const SkOpAngle* CoincidenceAngle(SkOpCoincidence*, int id); + SkOpContour* CoincidenceContour(SkOpCoincidence*, int id); + const SkOpPtT* CoincidencePtT(SkOpCoincidence*, int id); + const SkOpSegment* CoincidenceSegment(SkOpCoincidence*, int id); + const SkOpSpanBase* CoincidenceSpan(SkOpCoincidence*, int id); + + const SkOpAngle* PtTAngle(const SkOpPtT*, int id); + SkOpContour* PtTContour(SkOpPtT*, int id); + const SkOpPtT* PtTPtT(const SkOpPtT*, int id); + const SkOpSegment* PtTSegment(const SkOpPtT*, int id); + const SkOpSpanBase* PtTSpan(const SkOpPtT*, int id); + + const SkOpAngle* SegmentAngle(const SkOpSegment*, int id); + SkOpContour* SegmentContour(SkOpSegment*, int id); + const SkOpPtT* SegmentPtT(const SkOpSegment*, int id); + const SkOpSegment* SegmentSegment(const SkOpSegment*, int id); + const SkOpSpanBase* SegmentSpan(const SkOpSegment*, int id); + + const SkOpAngle* SpanAngle(const SkOpSpanBase*, int id); + SkOpContour* SpanContour(SkOpSpanBase*, int id); + const SkOpPtT* SpanPtT(const SkOpSpanBase*, int id); + const SkOpSegment* SpanSegment(const SkOpSpanBase*, int id); + const SkOpSpanBase* SpanSpan(const SkOpSpanBase*, int id); - static void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op, +#if DEBUG_DUMP_VERIFY + void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op, const char* testName); - static void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op, + void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op, const char* testName); - static void DumpSimplify(const SkPath& path, const char* testName); - static void DumpSimplify(FILE* file, const SkPath& path, const char* testName); - static void ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op); - static void ReportSimplifyFail(const SkPath& path); - static void VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op, + void DumpSimplify(const SkPath& path, const char* testName); + void DumpSimplify(FILE* file, const SkPath& path, const char* testName); + void ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op); + void ReportSimplifyFail(const SkPath& path); + void VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op, const SkPath& result); - static void VerifySimplify(const SkPath& path, const SkPath& result); + void VerifySimplify(const SkPath& path, const SkPath& result); #endif -#if DEBUG_ACTIVE_SPANS - static SkString gActiveSpans; -#endif - -}; - -struct SkDQuad; + // global path dumps for msvs Visual Studio 17 to use from Immediate Window + void Dump(const SkOpContour& ); + void DumpAll(const SkOpContour& ); + void DumpAngles(const SkOpContour& ); + void DumpContours(const SkOpContour& ); + void DumpContoursAll(const SkOpContour& ); + void DumpContoursAngles(const SkOpContour& ); + void DumpContoursPts(const SkOpContour& ); + void DumpContoursPt(const SkOpContour& , int segmentID); + void DumpContoursSegment(const SkOpContour& , int segmentID); + void DumpContoursSpan(const SkOpContour& , int segmentID); + void DumpContoursSpans(const SkOpContour& ); + void DumpPt(const SkOpContour& , int ); + void DumpPts(const SkOpContour& , const char* prefix = "seg"); + void DumpSegment(const SkOpContour& , int ); + void DumpSegments(const SkOpContour& , const char* prefix = "seg", SkPathOp op = (SkPathOp) -1); + void DumpSpan(const SkOpContour& , int ); + void DumpSpans(const SkOpContour& ); + + void Dump(const SkOpSegment& ); + void DumpAll(const SkOpSegment& ); + void DumpAngles(const SkOpSegment& ); + void DumpCoin(const SkOpSegment& ); + void DumpPts(const SkOpSegment& , const char* prefix = "seg"); + + void Dump(const SkOpPtT& ); + void DumpAll(const SkOpPtT& ); + + void Dump(const SkOpSpanBase& ); + void DumpCoin(const SkOpSpanBase& ); + void DumpAll(const SkOpSpanBase& ); + + void DumpCoin(const SkOpSpan& ); + bool DumpSpan(const SkOpSpan& ); + + void Dump(const SkDConic& ); + void DumpID(const SkDConic& , int id); + + void Dump(const SkDCubic& ); + void DumpID(const SkDCubic& , int id); + + void Dump(const SkDLine& ); + void DumpID(const SkDLine& , int id); + + void Dump(const SkDQuad& ); + void DumpID(const SkDQuad& , int id); + + void Dump(const SkDPoint& ); + +// dummy declarations to fool msvs Visual Studio 2018 Immediate Window +#define DummyDeclarations(a, b) \ + void Dump(const SkDebugTCoincident##a##b& ); \ + \ + void Dump(const SkDebugTSect##a##b& ); \ + void DumpBoth(const SkDebugTSect##a##b& , SkDebugTSect##a##b* ); \ + void DumpBounded(const SkDebugTSect##a##b& , int id); \ + void DumpBounds(const SkDebugTSect##a##b& ); \ + void DumpCoin(const SkDebugTSect##a##b& ); \ + void DumpCoinCurves(const SkDebugTSect##a##b& ); \ + void DumpCurves(const SkDebugTSect##a##b& ); \ + \ + void Dump(const SkDebugTSpan##a##b& ); \ + void DumpAll(const SkDebugTSpan##a##b& ); \ + void DumpBounded(const SkDebugTSpan##a##b& , int id); \ + void DumpBounds(const SkDebugTSpan##a##b& ); \ + void DumpCoin(const SkDebugTSpan##a##b& ) + + DummyDeclarations(Quad, Quad); + DummyDeclarations(Conic, Quad); + DummyDeclarations(Conic, Conic); + DummyDeclarations(Cubic, Quad); + DummyDeclarations(Cubic, Conic); + DummyDeclarations(Cubic, Cubic); +#undef DummyDeclarations +} // generates tools/path_sorter.htm and path_visualizer.htm compatible data void DumpQ(const SkDQuad& quad1, const SkDQuad& quad2, int testNo); void DumpT(const SkDQuad& quad, double t); +// global path dumps for msvs Visual Studio 17 to use from Immediate Window +void Dump(const SkPath& path); +void DumpHex(const SkPath& path); + #endif diff --git a/src/pathops/SkPathOpsTSect.h b/src/pathops/SkPathOpsTSect.h index 833e735da6..1e78f2a108 100644 --- a/src/pathops/SkPathOpsTSect.h +++ b/src/pathops/SkPathOpsTSect.h @@ -415,6 +415,7 @@ SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addFollowing( next->fPrev = result; } result->resetBounds(fCurve); + // world may not be consistent to call validate here result->validate(); return result; } @@ -1797,6 +1798,7 @@ void SkTSect<TCurve, OppCurve>::removeSpanRange(SkTSpan<TCurve, OppCurve>* first final->fPrev = first; } first->fNext = final; + // world may not be ready for validation here first->validate(); } @@ -1888,6 +1890,7 @@ bool SkTSect<TCurve, OppCurve>::unlinkSpan(SkTSpan<TCurve, OppCurve>* span) { if (next->fStartT > next->fEndT) { return false; } + // world may not be ready for validate here next->validate(); } } else { |