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