1/* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "fuzz/Fuzz.h" 9#include "fuzz/FuzzCommon.h" 10#include "include/core/SkPath.h" 11#include "include/core/SkRect.h" 12#include "include/pathops/SkPathOps.h" 13 14const uint8_t MAX_OPS = 20; 15 16DEF_FUZZ(Pathop, fuzz) { 17 18 uint8_t choice; 19 fuzz->nextRange(&choice, 0, 4); 20 switch (choice) { 21 case 0: { 22 uint8_t ops; 23 fuzz->nextRange(&ops, 0, MAX_OPS); 24 SkOpBuilder builder; 25 for (uint8_t i = 0; i < ops && !fuzz->exhausted(); i++) { 26 SkPath path; 27 FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); 28 SkPathFillType ft; 29 fuzz->nextRange(&ft, 0, (int)SkPathFillType::kInverseEvenOdd); 30 path.setFillType(ft); 31 32 SkPathOp op; 33 fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp); 34 builder.add(path, op); 35 } 36 37 SkPath result; 38 builder.resolve(&result); 39 break; 40 } 41 case 1: { 42 SkPath path; 43 FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); 44 SkPathFillType ft; 45 fuzz->nextRange(&ft, 0, (int)SkPathFillType::kInverseEvenOdd); 46 path.setFillType(ft); 47 48 SkPath result; 49 bool isSame; 50 fuzz->next(&isSame); 51 if (isSame) { 52 result = path; 53 } 54 Simplify(path, &result); 55 break; 56 } 57 case 2: { 58 SkPath path; 59 FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); 60 SkPathFillType ft; 61 fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd); 62 path.setFillType(ft); 63 64 SkPath path2; 65 FuzzEvilPath(fuzz, &path2, SkPath::Verb::kDone_Verb); 66 fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd); 67 path.setFillType(ft); 68 69 SkPathOp op; 70 fuzz->nextRange(&op, 0, SkPathOp::kReverseDifference_SkPathOp); 71 72 SkPath result; 73 uint8_t pickOutput; 74 fuzz->nextRange(&pickOutput, 0, 2); 75 if (pickOutput == 1) { 76 result = path; 77 } else if (pickOutput == 2) { 78 result = path2; 79 } 80 Op(path, path2, op, &result); 81 break; 82 } 83 case 3: { 84 SkPath path; 85 FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); 86 SkPathFillType ft; 87 fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd); 88 path.setFillType(ft); 89 90 SkPath result; 91 bool isSame; 92 fuzz->next(&isSame); 93 if (isSame) { 94 result = path; 95 } 96 AsWinding(path, &result); 97 break; 98 } 99 case 4: { 100 SkPath path; 101 FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); 102 SkPathFillType ft; 103 fuzz->nextRange(&ft, 0, SkPathFillType::kInverseEvenOdd); 104 path.setFillType(ft); 105 106 SkRect result; 107 TightBounds(path, &result); 108 break; 109 } 110 default: { 111 SkASSERT(false); 112 break; 113 } 114 } 115} 116 117 118const int kLastOp = SkPathOp::kReverseDifference_SkPathOp; 119 120void BuildPath(Fuzz* fuzz, SkPath* path) { 121 while (!fuzz->exhausted()) { 122 // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" 123 // smaller, which leads to more efficient fuzzing. 124 uint8_t operation; 125 fuzz->next(&operation); 126 SkScalar a,b,c,d,e,f; 127 128 switch (operation % (SkPath::Verb::kDone_Verb + 1)) { 129 case SkPath::Verb::kMove_Verb: 130 if (fuzz->remaining() < (2*sizeof(SkScalar))) { 131 fuzz->deplete(); 132 return; 133 } 134 fuzz->next(&a, &b); 135 path->moveTo(a, b); 136 break; 137 138 case SkPath::Verb::kLine_Verb: 139 if (fuzz->remaining() < (2*sizeof(SkScalar))) { 140 fuzz->deplete(); 141 return; 142 } 143 fuzz->next(&a, &b); 144 path->lineTo(a, b); 145 break; 146 147 case SkPath::Verb::kQuad_Verb: 148 if (fuzz->remaining() < (4*sizeof(SkScalar))) { 149 fuzz->deplete(); 150 return; 151 } 152 fuzz->next(&a, &b, &c, &d); 153 path->quadTo(a, b, c, d); 154 break; 155 156 case SkPath::Verb::kConic_Verb: 157 if (fuzz->remaining() < (5*sizeof(SkScalar))) { 158 fuzz->deplete(); 159 return; 160 } 161 fuzz->next(&a, &b, &c, &d, &e); 162 path->conicTo(a, b, c, d, e); 163 break; 164 165 case SkPath::Verb::kCubic_Verb: 166 if (fuzz->remaining() < (6*sizeof(SkScalar))) { 167 fuzz->deplete(); 168 return; 169 } 170 fuzz->next(&a, &b, &c, &d, &e, &f); 171 path->cubicTo(a, b, c, d, e, f); 172 break; 173 174 case SkPath::Verb::kClose_Verb: 175 path->close(); 176 break; 177 178 case SkPath::Verb::kDone_Verb: 179 // In this case, simply exit. 180 return; 181 } 182 } 183} 184 185DEF_FUZZ(LegacyChromiumPathop, fuzz) { 186 // See https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/skia_pathop_fuzzer.cc 187 SkOpBuilder builder; 188 while (!fuzz->exhausted()) { 189 SkPath path; 190 uint8_t op; 191 fuzz->next(&op); 192 if (fuzz->exhausted()) { 193 break; 194 } 195 196 BuildPath(fuzz, &path); 197 builder.add(path, static_cast<SkPathOp>(op % (kLastOp + 1))); 198 } 199 200 SkPath result; 201 builder.resolve(&result); 202} 203