|  | /* | 
|  | * 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); | 
|  | SkPathFillType ft; | 
|  | fuzz->nextRange(&ft, 0, (int)SkPathFillType::kInverseEvenOdd); | 
|  | 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); | 
|  | SkPathFillType ft; | 
|  | fuzz->nextRange(&ft, 0, (int)SkPathFillType::kInverseEvenOdd); | 
|  | 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); | 
|  | SkPathFillType ft; | 
|  | fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd); | 
|  | path.setFillType(ft); | 
|  |  | 
|  | SkPath path2; | 
|  | FuzzEvilPath(fuzz, &path2, SkPath::Verb::kDone_Verb); | 
|  | fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd); | 
|  | 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); | 
|  | SkPathFillType ft; | 
|  | fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd); | 
|  | 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); | 
|  | SkPathFillType ft; | 
|  | fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd); | 
|  | 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); | 
|  | } |