• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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