1 /*
2 * Copyright 2018 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 "src/core/SkPathPriv.h"
11
12 // We don't always want to test NaNs and infinities.
fuzz_nice_float(Fuzz * fuzz,float * f)13 static void fuzz_nice_float(Fuzz* fuzz, float* f) {
14 float v;
15 fuzz->next(&v);
16 constexpr float kLimit = 1.0e35f; // FLT_MAX?
17 *f = (v == v && v <= kLimit && v >= -kLimit) ? v : 0.0f;
18 }
19
20 template <typename... Args>
fuzz_nice_float(Fuzz * fuzz,float * f,Args...rest)21 static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) {
22 fuzz_nice_float(fuzz, f);
23 fuzz_nice_float(fuzz, rest...);
24 }
25
fuzz_nice_rect(Fuzz * fuzz,SkRect * r)26 static void fuzz_nice_rect(Fuzz* fuzz, SkRect* r) {
27 fuzz_nice_float(fuzz, &r->fLeft, &r->fTop, &r->fRight, &r->fBottom);
28 r->sort();
29 }
30
31 // allows some float values for path points
FuzzNicePath(Fuzz * fuzz,SkPath * path,int maxOps)32 void FuzzNicePath(Fuzz* fuzz, SkPath* path, int maxOps) {
33 if (maxOps <= 0 || fuzz->exhausted() || path->countPoints() > 100000) {
34 return;
35 }
36 uint8_t fillType;
37 fuzz->nextRange(&fillType, 0, (uint8_t)SkPathFillType::kInverseEvenOdd);
38 path->setFillType((SkPathFillType)fillType);
39 uint8_t numOps;
40 fuzz->nextRange(&numOps, 0, maxOps);
41 for (uint8_t i = 0; i < numOps; ++i) {
42 // When we start adding the path to itself, the fuzzer can make an
43 // exponentially long path, which causes timeouts.
44 if (path->countPoints() > 100000) {
45 return;
46 }
47 // How many items in the switch statement below.
48 constexpr uint8_t MAX_PATH_OPERATION = 32;
49 uint8_t op;
50 fuzz->nextRange(&op, 0, MAX_PATH_OPERATION);
51 bool test;
52 SkPath p;
53 SkMatrix m;
54 SkRRect rr;
55 SkRect r;
56 SkPathDirection dir;
57 unsigned int ui;
58 SkScalar a, b, c, d, e, f;
59 switch (op) {
60 case 0:
61 fuzz_nice_float(fuzz, &a, &b);
62 path->moveTo(a, b);
63 break;
64 case 1:
65 fuzz_nice_float(fuzz, &a, &b);
66 path->rMoveTo(a, b);
67 break;
68 case 2:
69 fuzz_nice_float(fuzz, &a, &b);
70 path->lineTo(a, b);
71 break;
72 case 3:
73 fuzz_nice_float(fuzz, &a, &b);
74 path->rLineTo(a, b);
75 break;
76 case 4:
77 fuzz_nice_float(fuzz, &a, &b, &c, &d);
78 path->quadTo(a, b, c, d);
79 break;
80 case 5:
81 fuzz_nice_float(fuzz, &a, &b, &c, &d);
82 path->rQuadTo(a, b, c, d);
83 break;
84 case 6:
85 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
86 path->conicTo(a, b, c, d, e);
87 break;
88 case 7:
89 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
90 path->rConicTo(a, b, c, d, e);
91 break;
92 case 8:
93 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
94 path->cubicTo(a, b, c, d, e, f);
95 break;
96 case 9:
97 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f);
98 path->rCubicTo(a, b, c, d, e, f);
99 break;
100 case 10:
101 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e);
102 path->arcTo(a, b, c, d, e);
103 break;
104 case 11:
105 fuzz_nice_float(fuzz, &a, &b);
106 fuzz_nice_rect(fuzz, &r);
107 fuzz->next(&test);
108 path->arcTo(r, a, b, test);
109 break;
110 case 12:
111 path->close();
112 break;
113 case 13:
114 fuzz_nice_rect(fuzz, &r);
115 fuzz->nextRange(&ui, 0, 1);
116 dir = static_cast<SkPathDirection>(ui);
117 path->addRect(r, dir);
118 break;
119 case 14:
120 fuzz->nextRange(&ui, 0, 1);
121 dir = static_cast<SkPathDirection>(ui);
122 fuzz_nice_rect(fuzz, &r);
123 fuzz->next(&ui);
124 path->addRect(r, dir, ui);
125 break;
126 case 15:
127 fuzz->nextRange(&ui, 0, 1);
128 dir = static_cast<SkPathDirection>(ui);
129 fuzz_nice_rect(fuzz, &r);
130 path->addOval(r, dir);
131 break;
132 case 16:
133 fuzz->nextRange(&ui, 0, 1);
134 dir = static_cast<SkPathDirection>(ui);
135 fuzz_nice_rect(fuzz, &r);
136 fuzz->next(&ui);
137 path->addOval(r, dir, ui);
138 break;
139 case 17:
140 fuzz->nextRange(&ui, 0, 1);
141 dir = static_cast<SkPathDirection>(ui);
142 fuzz_nice_float(fuzz, &a, &b, &c);
143 path->addCircle(a, b, c, dir);
144 break;
145 case 18:
146 fuzz_nice_rect(fuzz, &r);
147 fuzz_nice_float(fuzz, &a, &b);
148 path->addArc(r, a, b);
149 break;
150 case 19:
151 fuzz_nice_float(fuzz, &a, &b);
152 fuzz_nice_rect(fuzz, &r);
153 fuzz->nextRange(&ui, 0, 1);
154 dir = static_cast<SkPathDirection>(ui);
155 path->addRoundRect(r, a, b, dir);
156 break;
157 case 20:
158 FuzzNiceRRect(fuzz, &rr);
159 fuzz->nextRange(&ui, 0, 1);
160 dir = static_cast<SkPathDirection>(ui);
161 path->addRRect(rr, dir);
162 break;
163 case 21:
164 fuzz->nextRange(&ui, 0, 1);
165 dir = static_cast<SkPathDirection>(ui);
166 FuzzNiceRRect(fuzz, &rr);
167 path->addRRect(rr, dir, ui);
168 break;
169 case 22: {
170 fuzz->nextRange(&ui, 0, 1);
171 SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui);
172 FuzzNiceMatrix(fuzz, &m);
173 FuzzNicePath(fuzz, &p, maxOps-1);
174 path->addPath(p, m, mode);
175 break;
176 }
177 case 23: {
178 fuzz->nextRange(&ui, 0, 1);
179 SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui);
180 FuzzNiceMatrix(fuzz, &m);
181 path->addPath(*path, m, mode);
182 break;
183 }
184 case 24:
185 FuzzNicePath(fuzz, &p, maxOps-1);
186 path->reverseAddPath(p);
187 break;
188 case 25:
189 path->addPath(*path);
190 break;
191 case 26:
192 path->reverseAddPath(*path);
193 break;
194 case 27:
195 fuzz_nice_float(fuzz, &a, &b);
196 path->offset(a, b, path);
197 break;
198 case 28:
199 FuzzNicePath(fuzz, &p, maxOps-1);
200 fuzz_nice_float(fuzz, &a, &b);
201 p.offset(a, b, path);
202 break;
203 case 29:
204 FuzzNiceMatrix(fuzz, &m);
205 path->transform(m, path);
206 break;
207 case 30:
208 FuzzNicePath(fuzz, &p, maxOps-1);
209 // transform can explode path sizes so skip this op if p too big
210 if (p.countPoints() <= 100000) {
211 FuzzNiceMatrix(fuzz, &m);
212 p.transform(m, path);
213 }
214 break;
215 case 31:
216 fuzz_nice_float(fuzz, &a, &b);
217 path->setLastPt(a, b);
218 break;
219 case MAX_PATH_OPERATION:
220 SkPathPriv::ShrinkToFit(path);
221 break;
222
223 default:
224 SkASSERT(false);
225 break;
226 }
227 SkASSERTF( path->isValid(), "path->isValid() failed at op %d, case %d", i, op);
228 }
229 }
230
231 // allows all float values for path points
FuzzEvilPath(Fuzz * fuzz,SkPath * path,int last_verb)232 void FuzzEvilPath(Fuzz* fuzz, SkPath* path, int last_verb) {
233 while (!fuzz->exhausted()) {
234 // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint"
235 // smaller, which leads to more efficient fuzzing.
236 uint8_t operation;
237 fuzz->next(&operation);
238 SkScalar a,b,c,d,e,f;
239
240 switch (operation % (last_verb + 1)) {
241 case SkPath::Verb::kMove_Verb:
242 fuzz->next(&a, &b);
243 path->moveTo(a, b);
244 break;
245
246 case SkPath::Verb::kLine_Verb:
247 fuzz->next(&a, &b);
248 path->lineTo(a, b);
249 break;
250
251 case SkPath::Verb::kQuad_Verb:
252 fuzz->next(&a, &b, &c, &d);
253 path->quadTo(a, b, c, d);
254 break;
255
256 case SkPath::Verb::kConic_Verb:
257 fuzz->next(&a, &b, &c, &d, &e);
258 path->conicTo(a, b, c, d, e);
259 break;
260
261 case SkPath::Verb::kCubic_Verb:
262 fuzz->next(&a, &b, &c, &d, &e, &f);
263 path->cubicTo(a, b, c, d, e, f);
264 break;
265
266 case SkPath::Verb::kClose_Verb:
267 path->close();
268 break;
269
270 case SkPath::Verb::kDone_Verb:
271 // In this case, simply exit.
272 return;
273 }
274 }
275 }
276
FuzzNiceRRect(Fuzz * fuzz,SkRRect * rr)277 void FuzzNiceRRect(Fuzz* fuzz, SkRRect* rr) {
278 SkRect r;
279 fuzz_nice_rect(fuzz, &r);
280
281 SkVector radii[4];
282 for (SkVector& vec : radii) {
283 fuzz->nextRange(&vec.fX, 0.0f, 1.0f);
284 vec.fX *= 0.5f * r.width();
285 fuzz->nextRange(&vec.fY, 0.0f, 1.0f);
286 vec.fY *= 0.5f * r.height();
287 }
288 rr->setRectRadii(r, radii);
289 SkASSERT(rr->isValid());
290 }
291
FuzzNiceMatrix(Fuzz * fuzz,SkMatrix * m)292 void FuzzNiceMatrix(Fuzz* fuzz, SkMatrix* m) {
293 constexpr int kArrayLength = 9;
294 SkScalar buffer[kArrayLength];
295 int matrixType;
296 fuzz->nextRange(&matrixType, 0, 4);
297 switch (matrixType) {
298 case 0: // identity
299 *m = SkMatrix::I();
300 return;
301 case 1: // translate
302 fuzz->nextRange(&buffer[0], -4000.0f, 4000.0f);
303 fuzz->nextRange(&buffer[1], -4000.0f, 4000.0f);
304 *m = SkMatrix::Translate(buffer[0], buffer[1]);
305 return;
306 case 2: // translate + scale
307 fuzz->nextRange(&buffer[0], -400.0f, 400.0f);
308 fuzz->nextRange(&buffer[1], -400.0f, 400.0f);
309 fuzz->nextRange(&buffer[2], -4000.0f, 4000.0f);
310 fuzz->nextRange(&buffer[3], -4000.0f, 4000.0f);
311 *m = SkMatrix::Scale(buffer[0], buffer[1]);
312 m->postTranslate(buffer[2], buffer[3]);
313 return;
314 case 3: // affine
315 fuzz->nextN(buffer, 6);
316 m->setAffine(buffer);
317 return;
318 case 4: // perspective
319 fuzz->nextN(buffer, kArrayLength);
320 m->set9(buffer);
321 return;
322 default:
323 SkASSERT(false);
324 return;
325 }
326 }
327
FuzzNiceRegion(Fuzz * fuzz,SkRegion * region,int maxN)328 void FuzzNiceRegion(Fuzz* fuzz, SkRegion* region, int maxN) {
329 uint8_t N;
330 fuzz->nextRange(&N, 0, maxN);
331 for (uint8_t i = 0; i < N; ++i) {
332 SkIRect r;
333 SkRegion::Op op;
334 // Avoid the sentinel value used by Region.
335 fuzz->nextRange(&r.fLeft, -2147483646, 2147483646);
336 fuzz->nextRange(&r.fTop, -2147483646, 2147483646);
337 fuzz->nextRange(&r.fRight, -2147483646, 2147483646);
338 fuzz->nextRange(&r.fBottom, -2147483646, 2147483646);
339 r.sort();
340 fuzz->nextEnum(&op, SkRegion::kLastOp);
341 if (!region->op(r, op)) {
342 return;
343 }
344 }
345 }
346