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