/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "fuzz/Fuzz.h" #include "fuzz/FuzzCommon.h" #include "include/core/SkPath.h" #include "include/core/SkRect.h" #include "include/pathops/SkPathOps.h" const uint8_t MAX_OPS = 20; DEF_FUZZ(Pathop, fuzz) { uint8_t choice; fuzz->nextRange(&choice, 0, 4); switch (choice) { case 0: { uint8_t ops; fuzz->nextRange(&ops, 0, MAX_OPS); SkOpBuilder builder; for (uint8_t i = 0; i < ops && !fuzz->exhausted(); i++) { SkPath path; FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); SkPath::FillType ft; fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType); path.setFillType(ft); SkPathOp op; fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp); builder.add(path, op); } SkPath result; builder.resolve(&result); break; } case 1: { SkPath path; FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); SkPath::FillType ft; fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType); path.setFillType(ft); SkPath result; bool isSame; fuzz->next(&isSame); if (isSame) { result = path; } Simplify(path, &result); break; } case 2: { SkPath path; FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); SkPath::FillType ft; fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType); path.setFillType(ft); SkPath path2; FuzzEvilPath(fuzz, &path2, SkPath::Verb::kDone_Verb); fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType); path.setFillType(ft); SkPathOp op; fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp); SkPath result; uint8_t pickOutput; fuzz->nextRange(&pickOutput, 0, 2); if (pickOutput == 1) { result = path; } else if (pickOutput == 2) { result = path2; } Op(path, path2, op, &result); break; } case 3: { SkPath path; FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); SkPath::FillType ft; fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType); path.setFillType(ft); SkPath result; bool isSame; fuzz->next(&isSame); if (isSame) { result = path; } AsWinding(path, &result); break; } case 4: { SkPath path; FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); SkPath::FillType ft; fuzz->nextRange(&ft, 0, SkPath::kInverseEvenOdd_FillType); path.setFillType(ft); SkRect result; TightBounds(path, &result); break; } default: { SkASSERT(false); break; } } } const int kLastOp = SkPathOp::kReverseDifference_SkPathOp; void BuildPath(Fuzz* fuzz, SkPath* path) { while (!fuzz->exhausted()) { // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" // smaller, which leads to more efficient fuzzing. uint8_t operation; fuzz->next(&operation); SkScalar a,b,c,d,e,f; switch (operation % (SkPath::Verb::kDone_Verb + 1)) { case SkPath::Verb::kMove_Verb: if (fuzz->remaining() < (2*sizeof(SkScalar))) { fuzz->deplete(); return; } fuzz->next(&a, &b); path->moveTo(a, b); break; case SkPath::Verb::kLine_Verb: if (fuzz->remaining() < (2*sizeof(SkScalar))) { fuzz->deplete(); return; } fuzz->next(&a, &b); path->lineTo(a, b); break; case SkPath::Verb::kQuad_Verb: if (fuzz->remaining() < (4*sizeof(SkScalar))) { fuzz->deplete(); return; } fuzz->next(&a, &b, &c, &d); path->quadTo(a, b, c, d); break; case SkPath::Verb::kConic_Verb: if (fuzz->remaining() < (5*sizeof(SkScalar))) { fuzz->deplete(); return; } fuzz->next(&a, &b, &c, &d, &e); path->conicTo(a, b, c, d, e); break; case SkPath::Verb::kCubic_Verb: if (fuzz->remaining() < (6*sizeof(SkScalar))) { fuzz->deplete(); return; } fuzz->next(&a, &b, &c, &d, &e, &f); path->cubicTo(a, b, c, d, e, f); break; case SkPath::Verb::kClose_Verb: path->close(); break; case SkPath::Verb::kDone_Verb: // In this case, simply exit. return; } } } DEF_FUZZ(LegacyChromiumPathop, fuzz) { // See https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/skia_pathop_fuzzer.cc SkOpBuilder builder; while (!fuzz->exhausted()) { SkPath path; uint8_t op; fuzz->next(&op); if (fuzz->exhausted()) { break; } BuildPath(fuzz, &path); builder.add(path, static_cast<SkPathOp>(op % (kLastOp + 1))); } SkPath result; builder.resolve(&result); }